<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  

  
  <title>Abel&#39;Blog</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <meta property="og:type" content="website">
<meta property="og:title" content="Abel&#39;Blog">
<meta property="og:url" content="http://example.com/page/2/index.html">
<meta property="og:site_name" content="Abel&#39;Blog">
<meta property="og:locale" content="en_US">
<meta property="article:author" content="Abel Sean">
<meta name="twitter:card" content="summary">
  
    <link rel="alternate" href="/atom.xml" title="Abel&#39;Blog" type="application/atom+xml">
  
  
    <link rel="icon" href="/favicon.png">
  
  
    <link href="//fonts.googleapis.com/css?family=Source+Code+Pro" rel="stylesheet" type="text/css">
  
  
<link rel="stylesheet" href="/css/style.css">

<meta name="generator" content="Hexo 5.4.0"></head>

<body>
  <div id="container">
    <div id="wrap">
      <header id="header">
  <div id="banner"></div>
  <div id="header-outer" class="outer">
    <div id="header-title" class="inner">
      <h1 id="logo-wrap">
        <a href="/" id="logo">Abel&#39;Blog</a>
      </h1>
      
    </div>
    <div id="header-inner" class="inner">
      <nav id="main-nav">
        <a id="main-nav-toggle" class="nav-icon"></a>
        
          <a class="main-nav-link" href="/">Home</a>
        
          <a class="main-nav-link" href="/archives">Archives</a>
        
      </nav>
      <nav id="sub-nav">
        
          <a id="nav-rss-link" class="nav-icon" href="/atom.xml" title="RSS Feed"></a>
        
        <a id="nav-search-btn" class="nav-icon" title="Search"></a>
      </nav>
      <div id="search-form-wrap">
        <form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" class="search-form-input" placeholder="Search"><button type="submit" class="search-form-submit">&#xF002;</button><input type="hidden" name="sitesearch" value="http://example.com"></form>
      </div>
    </div>
  </div>
</header>
      <div class="outer">
        <section id="main">
  
    <article id="post-2021/2021-03-15-BEHAVIOR3EDITOR学习" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2021/03/15/2021/2021-03-15-BEHAVIOR3EDITOR%E5%AD%A6%E4%B9%A0/" class="article-date">
  <time datetime="2021-03-14T16:00:00.000Z" itemprop="datePublished">2021-03-15</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2021/03/15/2021/2021-03-15-BEHAVIOR3EDITOR%E5%AD%A6%E4%B9%A0/">Behavior3Editor批量导出改造</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <ul>
<li><a href="#%E5%BC%80%E5%A7%8B%E9%83%A8%E7%BD%B2%E7%8E%AF%E5%A2%83">开始部署环境</a><ul>
<li><a href="#%E5%AE%89%E8%A3%85%E7%8E%AF%E5%A2%83">安装环境</a></li>
<li><a href="#%E8%AE%BE%E7%BD%AE%E6%A2%AF%E5%AD%90">设置梯子</a></li>
<li><a href="#%E9%81%87%E5%88%B0%E7%9A%84%E9%97%AE%E9%A2%98">遇到的问题</a><ul>
<li><a href="#nodegulp%E7%89%88%E6%9C%AC%E4%B8%8D%E5%90%88">node，gulp版本不合</a></li>
<li><a href="#%E5%9C%A8%E5%81%9Adist%E7%9A%84%E6%97%B6%E5%80%99%E8%BF%98%E6%98%AF%E4%BC%9A%E4%B8%8B%E8%BD%BDelectronc">在做dist的时候，还是会下载electronc</a></li>
<li><a href="#%E6%96%87%E4%BB%B6%E5%8D%A0%E7%94%A8">文件占用</a></li>
<li><a href="#%E4%BF%AE%E6%94%B9gulpfilejs">修改gulpfile.js</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#%E6%89%B9%E9%87%8F%E5%AF%BC%E5%87%BA%E5%AD%90%E6%A0%91%E6%BA%90%E7%A0%81">批量导出子树源码</a></li>
<li><a href="#%E5%A2%9E%E5%8A%A0%E7%9B%AE%E5%BD%95%E7%9A%84%E6%94%AF%E6%8C%81">增加目录的支持</a></li>
<li><a href="#%E5%8F%82%E8%80%83">参考</a></li>
</ul>
<p>项目里面需要将行为树project批量的导出子树。</p>
<p><a target="_blank" rel="noopener" href="https://github.com/swordhell/behavior3editor">源代码</a></p>
<h1 id="开始部署环境"><a href="#开始部署环境" class="headerlink" title="开始部署环境"></a>开始部署环境</h1><h2 id="安装环境"><a href="#安装环境" class="headerlink" title="安装环境"></a>安装环境</h2><p>将node.js 设置成 10.x win32版本，再去匹配 gulp 的版本。</p>
<p>通过命令行安装gulp工具。</p>
<figure class="highlight bat"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">npm install gulp-cli -g</span><br><span class="line">npm install gulp -D</span><br><span class="line">npx -p touch nodetouch gulpfile.js</span><br><span class="line">gulp --<span class="built_in">help</span></span><br></pre></td></tr></table></figure>

<h2 id="设置梯子"><a href="#设置梯子" class="headerlink" title="设置梯子"></a>设置梯子</h2><figure class="highlight bat"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">npm config <span class="built_in">set</span> registry http://registry.npm.taobao.org</span><br><span class="line"></span><br><span class="line">其实就是 .npmrc</span><br><span class="line"></span><br><span class="line">registry=http://registry.npm.taobao.org</span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">@REM 将npm的缓存都删除掉</span></span><br><span class="line">npm cache clear --force</span><br><span class="line"></span><br><span class="line">// 配置梯子，否则就会无法安装；</span><br><span class="line">Add the below entry to your .bowerrc:</span><br><span class="line">&#123;</span><br><span class="line">  &quot;proxy&quot;:&quot;http://&lt;user&gt;:&lt;password&gt;@&lt;host&gt;:&lt;port&gt;&quot;,</span><br><span class="line">  &quot;https-proxy&quot;:&quot;http://&lt;user&gt;:&lt;password&gt;@&lt;host&gt;:&lt;port&gt;&quot;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="遇到的问题"><a href="#遇到的问题" class="headerlink" title="遇到的问题"></a>遇到的问题</h2><figure class="highlight bat"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">bower sweetalert#~<span class="number">1</span>.<span class="number">0</span>.<span class="number">0</span>-beta              cached https://github.com/t4t5/sweetalert.git#<span class="number">1</span>.<span class="number">0</span>.<span class="number">1</span></span><br><span class="line">bower sweetalert#~<span class="number">1</span>.<span class="number">0</span>.<span class="number">0</span>-beta            validate <span class="number">1</span>.<span class="number">0</span>.<span class="number">1</span> against https://github.com/t4t5/sweetalert.git#~<span class="number">1</span>.<span class="number">0</span>.<span class="number">0</span>-beta</span><br><span class="line">bower fontawesome#~<span class="number">4</span>.<span class="number">3</span>.<span class="number">0</span>                 ECMDERR Failed to execute &quot;git ls-remote --tags --heads https://github.com/FortAwesome/Font-Awesome.git&quot;, <span class="keyword">exit</span> code of #<span class="number">128</span> fatal: unable </span><br><span class="line">to access &#x27;https://github.com/FortAwesome/Font-Awesome.git/&#x27;: Failed to connect to github.com port <span class="number">443</span>: Timed out</span><br><span class="line"></span><br><span class="line">Additional error details:</span><br><span class="line"><span class="function">fatal: <span class="title">unable</span> <span class="title">to</span> <span class="title">access</span> &#x27;<span class="title">https</span>://<span class="title">github.com</span>/<span class="title">FortAwesome</span>/<span class="title">Font</span>-<span class="title">Awesome.git</span>/&#x27;: <span class="title">Failed</span> <span class="title">to</span> <span class="title">connect</span> <span class="title">to</span> <span class="title">github.com</span> <span class="title">port</span> 443: <span class="title">Timed</span> <span class="title">out</span></span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function">// 配置梯子，否则就会无法安装；</span></span><br><span class="line"><span class="function"><span class="title">Add</span> <span class="title">the</span> <span class="title">below</span> <span class="title">entry</span> <span class="title">to</span> <span class="title">your</span> .<span class="title">bowerrc</span>:</span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function">&#123;</span></span><br><span class="line"><span class="function">  &quot;<span class="title">proxy</span>&quot;:&quot;<span class="title">http</span>://&lt;<span class="title">user</span>&gt;:&lt;<span class="title">password</span>&gt;@&lt;<span class="title">host</span>&gt;:&lt;<span class="title">port</span>&gt;&quot;,</span></span><br><span class="line"><span class="function">  &quot;<span class="title">https</span>-<span class="title">proxy</span>&quot;:&quot;<span class="title">http</span>://&lt;<span class="title">user</span>&gt;:&lt;<span class="title">password</span>&gt;@&lt;<span class="title">host</span>&gt;:&lt;<span class="title">port</span>&gt;&quot;</span></span><br><span class="line"><span class="function">&#125;</span></span><br></pre></td></tr></table></figure>

<p>当下载实在不行的时候，可以直接通过github里面下载源码，然后直接放到目录中。</p>
<p>目录说明</p>
<figure class="highlight bat"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">bower_components   // bower 支持库目录</span><br><span class="line">  |</span><br><span class="line">  ----angular-<span class="built_in">tree</span>-control</span><br><span class="line">  |</span><br><span class="line">  ----...</span><br><span class="line">.temp-dist         // 打包输出exe的目录</span><br><span class="line">  |</span><br><span class="line">  |</span><br><span class="line">  ----behavior3editor-win32-ia32      // win32版本的exe</span><br><span class="line">  |</span><br><span class="line">  ----...</span><br><span class="line">node_modules      // node.js 支持库目录</span><br></pre></td></tr></table></figure>

<h3 id="node，gulp版本不合"><a href="#node，gulp版本不合" class="headerlink" title="node，gulp版本不合"></a>node，gulp版本不合</h3><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">PS</span> D:\work\trunk\behavior3editor_bf&gt; gulp serve</span><br><span class="line">ReferenceError: primordials is not defined</span><br><span class="line">    at fs.js:<span class="number">45</span>:<span class="number">5</span></span><br><span class="line">    at req_ (D:\work\trunk\behavior3editor_bf\node_modules\natives\index.js:<span class="number">143</span>:<span class="number">24</span>)</span><br><span class="line">    at Object.req [<span class="type">as</span> <span class="type">require</span>] (D:\work\trunk\behavior3editor_bf\node_modules\natives\index.js:<span class="number">55</span>:<span class="number">10</span>)</span><br><span class="line">    at Object.&lt;anonymous&gt; (D:\work\trunk\behavior3editor_bf\node_modules\graceful<span class="literal">-fs</span>\fs.js:<span class="number">1</span>:<span class="number">37</span>)</span><br><span class="line">    at Module._compile (internal/modules/cjs/loader.js:<span class="number">1063</span>:<span class="number">30</span>)</span><br><span class="line">    at Object.Module._extensions..js (internal/modules/cjs/loader.js:<span class="number">1092</span>:<span class="number">10</span>)</span><br><span class="line">    at Module.load (internal/modules/cjs/loader.js:<span class="number">928</span>:<span class="number">32</span>)</span><br><span class="line">    at Function.Module._load (internal/modules/cjs/loader.js:<span class="number">769</span>:<span class="number">14</span>)</span><br><span class="line">    at Module.require (internal/modules/cjs/loader.js:<span class="number">952</span>:<span class="number">19</span>)</span><br><span class="line">    at require (internal/modules/cjs/helpers.js:<span class="number">88</span>:<span class="number">18</span>)</span><br><span class="line"></span><br><span class="line">&gt; node -<span class="literal">-version</span></span><br><span class="line">v14.<span class="number">16.0</span></span><br><span class="line">&gt; gulp <span class="literal">-v</span></span><br><span class="line"><span class="built_in">CLI</span> version: <span class="number">2.3</span>.<span class="number">0</span></span><br><span class="line">Local version: <span class="number">3.9</span>.<span class="number">1</span></span><br></pre></td></tr></table></figure>

<p>解决方案：</p>
<figure class="highlight bat"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">##安装npm版本控制器</span><br><span class="line">npm install -g n</span><br><span class="line"></span><br><span class="line">##切换npm版本到 V10 (v10 版本的npm会安装 node <span class="number">10</span>)</span><br><span class="line">sudo n v10.<span class="number">19</span>.<span class="number">0</span></span><br><span class="line"></span><br><span class="line">##安装node</span><br><span class="line">npm i -g node</span><br><span class="line"></span><br><span class="line">##查看node版本</span><br><span class="line">node --version</span><br><span class="line"></span><br><span class="line">##现在node版本切换到了v10了，可以重新安装依赖的</span><br><span class="line">    #重新安装gulp（版本很重要，应该是代码发布时的版本，而不是本地的版本）</span><br><span class="line">    npm i -g gulp@<span class="number">3</span>.<span class="number">9</span>.<span class="number">1</span> --force</span><br><span class="line">    #重新安装依赖</span><br><span class="line">    npm install</span><br><span class="line"></span><br><span class="line">npm install -g nvm</span><br><span class="line"></span><br><span class="line">##运行</span><br><span class="line">gulp watch</span><br><span class="line">————————————————</span><br><span class="line">版权声明：本文为CSDN博主「内心毫无波动甚至还想笑」的原创文章，遵循CC <span class="number">4</span>.<span class="number">0</span> BY-SA版权协议，转载请附上原文出处链接及本声明。</span><br><span class="line">原文链接：https://blog.csdn.<span class="built_in">net</span>/yym836659673/article/details/<span class="number">104847572</span>/</span><br></pre></td></tr></table></figure>

<p>将node.js降低到 10.x版本，再去匹配 gulp 的版本。</p>
<p><a target="_blank" rel="noopener" href="https://nodejs.org/dist/latest-v10.x/">node.js_10.x版本下载</a></p>
<h3 id="在做dist的时候，还是会下载electronc"><a href="#在做dist的时候，还是会下载electronc" class="headerlink" title="在做dist的时候，还是会下载electronc"></a>在做dist的时候，还是会下载electronc</h3><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Downloading electron<span class="literal">-v0</span>.<span class="number">34.2</span><span class="literal">-linux</span><span class="literal">-ia32</span>.zip</span><br><span class="line">[&gt;                                            ] <span class="number">0.0</span>% (<span class="number">0</span> B/s)</span><br></pre></td></tr></table></figure>

<p>还需要安装：</p>
<p><a target="_blank" rel="noopener" href="https://github.com/electron/electron/releases/tag/v0.30.4">electron_v0.30.4下载地址</a><br>electron v0.34.2</p>
<p>国内下载地址：</p>
<p><a target="_blank" rel="noopener" href="https://npm.taobao.org/mirrors/electron/0.34.2/">国内源</a></p>
<p>使用<code>electron v0.34.2</code>的时候，需要使用<code>Node 8.x</code>版本的node.js。最后发布时间：17-Dec-2019 07:08</p>
<p><a target="_blank" rel="noopener" href="https://nodejs.org/dist/latest-v8.x/node-v8.17.0-x64.msi">下载页面</a></p>
<figure class="highlight bat"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">The Node version <span class="keyword">in</span> &quot;E:/electron-v0.<span class="number">34</span>.<span class="number">2</span>-win32-ia32/electron.exe&quot; is outdated (version ), we require <span class="built_in">at</span> least Node <span class="number">8</span>.x. Would you like to try debugging anyway?</span><br></pre></td></tr></table></figure>

<p>electron里面调整界面都是通过html来制作的。</p>
<p><code>variables.less</code>文件里面<code>@size-sidebar: 500px;</code>修改了之后，可以让弹出框更加大。</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">var stat = fs.statSync(subPath);</span><br><span class="line">if (!stat.isDirectory())</span><br><span class="line">&#123;</span><br><span class="line">  fs.mkdirSync(subPath, &#123; recursive: <span class="literal">true</span> &#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="文件占用"><a href="#文件占用" class="headerlink" title="文件占用"></a>文件占用</h3><p>打开资源管理器。</p>
<figure class="highlight bat"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">resmon.exe</span><br></pre></td></tr></table></figure>

<p>其实就是vscode的powershell占用了文件。重启一次vscode就好了。</p>
<h3 id="修改gulpfile-js"><a href="#修改gulpfile-js" class="headerlink" title="修改gulpfile.js"></a>修改gulpfile.js</h3><p>在这个文件里面，定义输出的版本是 windows arch类型： i32 就好了。</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">gulp.task(&#x27;_electron&#x27;, [&#x27;build&#x27;], function(cb) &#123;</span><br><span class="line">  packager(&#123;</span><br><span class="line">    dir       : &#x27;build&#x27;,</span><br><span class="line">    out       : &#x27;.temp-dist&#x27;,</span><br><span class="line">    name      : project.name,</span><br><span class="line">    platform  : &#x27;win32&#x27;,</span><br><span class="line">    arch      : &#x27;ia32&#x27;,</span><br><span class="line">    version   : &#x27;<span class="number">0.34</span><span class="number">.2</span>&#x27;,</span><br><span class="line">    overwrite : <span class="literal">true</span>,</span><br><span class="line">    asar      : <span class="literal">true</span></span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure>

<p>由于网络情况，如果想把全部平台的库都下载全了，也是比较困难的。</p>
<h1 id="批量导出子树源码"><a href="#批量导出子树源码" class="headerlink" title="批量导出子树源码"></a>批量导出子树源码</h1><p>改造的位置：</p>
<p>export.controller.js: 75 lines</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">save</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function">      &#125;<span class="title">else</span> <span class="title">if</span> (<span class="params">vm.type === <span class="string">&#x27;trees&#x27;</span></span>) </span>&#123;</span><br><span class="line">        dialogService</span><br><span class="line">          .openDirectory()</span><br><span class="line">          .then(<span class="function"><span class="keyword">function</span>(<span class="params">path</span>)</span>&#123;</span><br><span class="line">            tree = project.trees.each(<span class="function"><span class="keyword">function</span>(<span class="params">tree</span>) </span>&#123;</span><br><span class="line">              <span class="keyword">var</span> root = tree.blocks.getRoot();</span><br><span class="line">              defaultName = root.title;</span><br><span class="line">              <span class="keyword">var</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>);</span><br><span class="line">              <span class="keyword">var</span> e = $window.editor.export;</span><br><span class="line">              _createJson(e.treeToData(tree))</span><br><span class="line">              <span class="built_in">console</span>.log(vm.pretty)</span><br><span class="line">              fs.writeFileSync(path +<span class="string">&#x27;/&#x27;</span>+defaultName +<span class="string">&#x27;.json&#x27;</span>, vm.pretty)</span><br><span class="line">              notificationService.success(</span><br><span class="line">                <span class="string">&#x27;File path&#x27;</span>,</span><br><span class="line">                defaultName +<span class="string">&#x27;.json&#x27;</span></span><br><span class="line">              );</span><br><span class="line">            &#125;);</span><br><span class="line">            </span><br><span class="line">          &#125;);</span><br><span class="line">        </span><br><span class="line">      &#125;</span><br></pre></td></tr></table></figure>

<p>其实就是将project.trees遍历；</p>
<p>将tree内容萃取出json；</p>
<p>直接使用fs模块，同步写入文件；</p>
<p>dialogService.openDirectory()能让用户自己指定输出目录；</p>
<p>notificationService.success()将日志输出到屏幕上；</p>
<p>我现在还不会如何调试，阅读了一点eletronc的文档，东西不少，今后有时间再来学习。</p>
<p>调试功能还是支持的</p>
<p>gulp serve</p>
<p><a target="_blank" rel="noopener" href="https://imgtu.com/i/6HhDc6"><img src="https://z3.ax1x.com/2021/03/24/6HhDc6.png" alt="6HhDc6.png"></a></p>
<p>在node.js中又很多丰富的库，所以使用这个来编写程序时候，多想想有没有三方库。这点类似python。</p>
<h1 id="增加目录的支持"><a href="#增加目录的支持" class="headerlink" title="增加目录的支持"></a>增加目录的支持</h1><p>在半年前，behavior3editor 作者在对这个编辑器做了一些提升，添加了path的概念。</p>
<p>src\app\pages\editor\components\menubar.html</p>
<p>文件里面可以修改界面。</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">li</span>&gt;</span><span class="tag">&lt;<span class="name">a</span> <span class="attr">ng-click</span>=<span class="string">&quot;menubar.onExportTreesJson()&quot;</span>&gt;</span>Batch export trees as JSON<span class="tag">&lt;/<span class="name">a</span>&gt;</span><span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>用了调试器，将会加快编写工作。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Cannot <span class="built_in">read</span> property <span class="string">&#x27;length&#x27;</span> of undefined</span><br></pre></td></tr></table></figure>

<p>在这套代码里面的目录规划</p>
<p>处在根目录的文件：</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">&quot;version&quot;</span>: <span class="string">&quot;0.3.0&quot;</span>,</span><br><span class="line">  <span class="attr">&quot;scope&quot;</span>: <span class="string">&quot;tree&quot;</span>,</span><br><span class="line">  <span class="attr">&quot;id&quot;</span>: <span class="string">&quot;62d315fa-c8bf-4fa2-9205-89cd6a1c5062&quot;</span>,</span><br><span class="line">  <span class="attr">&quot;title&quot;</span>: <span class="string">&quot;BasicMonster&quot;</span>,</span><br><span class="line">  <span class="attr">&quot;description&quot;</span>: <span class="string">&quot;&quot;</span>,</span><br><span class="line">  <span class="attr">&quot;root&quot;</span>: <span class="string">&quot;6bb72df3-2b86-4cf4-8d43-d0c2c52e49c4&quot;</span>,</span><br><span class="line">  <span class="attr">&quot;properties&quot;</span>: &#123;&#125;,</span><br><span class="line">  <span class="attr">&quot;parent&quot;</span>: <span class="literal">null</span>,</span><br><span class="line"></span><br><span class="line">  <span class="attr">&quot;custom_folders&quot;</span>: [</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">&quot;version&quot;</span>: <span class="string">&quot;0.3.0&quot;</span>,</span><br><span class="line">      <span class="attr">&quot;scope&quot;</span>: <span class="string">&quot;folder&quot;</span>,</span><br><span class="line">      <span class="attr">&quot;name&quot;</span>: <span class="string">&quot;f8f5b0bd-285e-400b-85f4-8ab673ea4fe8&quot;</span>,</span><br><span class="line">      <span class="attr">&quot;category&quot;</span>: <span class="string">&quot;tree&quot;</span>,</span><br><span class="line">      <span class="attr">&quot;title&quot;</span>: <span class="string">&quot;ai&quot;</span>,</span><br><span class="line">      <span class="attr">&quot;description&quot;</span>: <span class="string">&quot;ai子目录；&quot;</span>,</span><br><span class="line">      <span class="attr">&quot;parent&quot;</span>: <span class="literal">null</span></span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<p>tree 能被 folders 包含，folders也能设置parent。</p>
<p>当导出的时候，我们就能使用这个custom_folders来创建本地目录。</p>
<p>通过fs来迭代创建目录。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">fs.mkdir(subPath, &#123; <span class="attr">recursive</span>: <span class="literal">true</span> &#125;, <span class="function"><span class="keyword">function</span>(<span class="params">err</span>) </span>&#123;&#125;);</span><br></pre></td></tr></table></figure>

<p>读取tree的folders信息：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 迭代方式读取目录结构</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">_fetchSubPath</span>(<span class="params">parent,custom_folders</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> retStr = <span class="string">&quot;&quot;</span>;</span><br><span class="line">  <span class="keyword">var</span> node;</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; custom_folders.length; i++) &#123;</span><br><span class="line">    <span class="keyword">if</span> (custom_folders[i].name == parent) &#123;</span><br><span class="line">      node = custom_folders[i];</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> (node.parent == <span class="literal">undefined</span>) &#123;</span><br><span class="line">    retStr = <span class="string">&quot;/&quot;</span> + node.title;</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    retStr = _fetchSubPath(node.parent,custom_folders) + <span class="string">&quot;/&quot;</span> + node.title;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> retStr;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">_createJson</span>(<span class="params">data</span>) </span>&#123;</span><br><span class="line">  vm.data = data;</span><br><span class="line">  vm.compact = JSON3.stringify(data);</span><br><span class="line">  vm.pretty = JSON3.stringify(data, <span class="literal">null</span>, <span class="number">2</span>);</span><br><span class="line">  vm.result = vm.pretty;</span><br><span class="line">  vm.subPath = <span class="string">&quot;/&quot;</span>;</span><br><span class="line">  <span class="keyword">if</span> (data.parent == <span class="literal">undefined</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> (data.custom_folders == <span class="literal">undefined</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">// 从custom_folders读取目录信息。</span></span><br><span class="line">  vm.subPath = _fetchSubPath(data.parent,data.custom_folders) + <span class="string">&quot;/&quot;</span>;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>导出部分代码， export.controller.js function save()</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (vm.type === <span class="string">&#x27;trees&#x27;</span>) &#123;</span><br><span class="line">        dialogService</span><br><span class="line">          .openDirectory()</span><br><span class="line">          .then(<span class="function"><span class="keyword">function</span>(<span class="params">path</span>)</span>&#123;</span><br><span class="line">            tree = project.trees.each(<span class="function"><span class="keyword">function</span>(<span class="params">tree</span>) </span>&#123;</span><br><span class="line">              <span class="keyword">var</span> root = tree.blocks.getRoot();</span><br><span class="line">              defaultName = root.title;</span><br><span class="line">              <span class="keyword">var</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>);</span><br><span class="line">              <span class="keyword">var</span> e = $window.editor.export;</span><br><span class="line">              _createJson(e.treeToData(tree));</span><br><span class="line">              <span class="keyword">var</span> subPath = path +vm.subPath;</span><br><span class="line">              <span class="comment">// 防止子目录没有。</span></span><br><span class="line">              fs.mkdir(subPath, &#123; <span class="attr">recursive</span>: <span class="literal">true</span> &#125;, <span class="function"><span class="keyword">function</span>(<span class="params">err</span>) </span>&#123;&#125;);</span><br><span class="line">              <span class="comment">// 再次导出，忽略掉custom_folders，减少json文件大小。</span></span><br><span class="line">              _createJson(e.treeToData(tree,<span class="literal">true</span>));</span><br><span class="line">              fs.writeFileSync(subPath+defaultName +<span class="string">&#x27;.json&#x27;</span>, vm.pretty);</span><br><span class="line">              notificationService.success(</span><br><span class="line">                <span class="string">&#x27;File saved&#x27;</span>,</span><br><span class="line">                defaultName +<span class="string">&#x27;.json&#x27;</span></span><br><span class="line">              );</span><br><span class="line">            &#125;);</span><br><span class="line">          &#125;);</span><br><span class="line">      &#125;</span><br></pre></td></tr></table></figure>

<p><a target="_blank" rel="noopener" href="https://blog.csdn.net/aerchi/article/details/106348750">https://blog.csdn.net/aerchi/article/details/106348750</a></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">A JavaScript error occured in the main process</span><br></pre></td></tr></table></figure>

<p>无法启动electron的desktop版本。</p>
<p>在代码里面有一份尝试创建目录的代码：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">_createIfNonExist</span>(<span class="params">path</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">try</span> &#123;</span><br><span class="line">    <span class="keyword">var</span> s = nodejsService.fs.statSync(path);</span><br><span class="line">  &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">    nodejsService.fs.mkdirSync(path);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>弹出框是通过 notification.service.js function _note(config)</p>
<p>里面的html可以定义这套显示的东西。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> DEFAULT = &#123;</span><br><span class="line">  <span class="attr">type</span>    : <span class="string">&#x27;default&#x27;</span>,</span><br><span class="line">  <span class="attr">title</span>   : <span class="string">&#x27;&#x27;</span>,</span><br><span class="line">  <span class="attr">message</span> : <span class="string">&#x27;&#x27;</span>,</span><br><span class="line">  <span class="attr">icon</span>    : <span class="literal">false</span>,</span><br><span class="line">  <span class="attr">delay</span>   : <span class="number">10000</span>, <span class="comment">// 将显示的时间延长</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;notification-message&quot;</span> <span class="attr">style</span>=<span class="string">&quot; width:590px;</span></span></span><br><span class="line"><span class="string"><span class="tag">// 调整显示区域；</span></span></span><br></pre></td></tr></table></figure>

<p>界面还是通过 class 来做渲染，使用了 less 决定了界面样式。</p>
<p>最后使用的文件为 c_notification.less 文件。</p>
<figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 决定了宽度</span></span><br><span class="line"><span class="attribute">width</span>: <span class="variable">@size-sidebar</span>+<span class="variable">@icon-size</span>;</span><br><span class="line"><span class="comment">// 将这个数据从 200px -&gt; 1000px</span></span><br><span class="line"><span class="variable">@add-ntf-size :</span> <span class="number">1000px</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 对这些地方增加宽度</span></span><br><span class="line"><span class="attribute">width</span>: <span class="variable">@size-sidebar</span>+<span class="variable">@icon-size</span>+-<span class="variable">@add-ntf-size</span>;</span><br><span class="line"><span class="attribute">right</span>: -<span class="variable">@size-sidebar</span>+-<span class="variable">@icon-size</span>+-<span class="variable">@add-ntf-size</span>;</span><br></pre></td></tr></table></figure>

<p>最近将node.js版本降级到  v8.17.0 结果不能支持迭代创建目录了。尝试将版本升级到 v10.x 再来尝试，果然好了。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>);</span><br><span class="line"><span class="keyword">var</span> subPath=<span class="string">&#x27;E:/work_client/server/res/ai/base/SubTree/&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// subPath</span></span><br><span class="line">fs.mkdir(subPath, &#123; <span class="attr">recursive</span>: <span class="literal">true</span> &#125;, <span class="function"><span class="keyword">function</span>(<span class="params">err</span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(err)</span><br><span class="line">&#125;);</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><ul>
<li>[1] <a target="_blank" rel="noopener" href="https://github.com/magicsea/behavior3editor">Behavior3editor源码</a></li>
<li>[2] <a target="_blank" rel="noopener" href="https://stackoverflow.com/questions/18359887/bower-proxy-configuration">bowerrc配置项目</a></li>
<li>[3] <a target="_blank" rel="noopener" href="https://stackoverflow.com/questions/15669091/bower-install-using-only-https">git地址从https转成git</a></li>
<li>[4] <a target="_blank" rel="noopener" href="https://blog.csdn.net/sunny_desmond/article/details/107506626">解决 ReferenceError: primordials is not defined</a></li>
<li>[5] <a target="_blank" rel="noopener" href="https://stackoverflow.com/questions/55212864/error-ebusy-resource-busy-or-locked-rmdir">ebusy-resouce-busy</a></li>
<li>[6] <a target="_blank" rel="noopener" href="https://www.electronjs.org/">electronjs官网</a></li>
</ul>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://example.com/2021/03/15/2021/2021-03-15-BEHAVIOR3EDITOR%E5%AD%A6%E4%B9%A0/" data-id="ckrn3an7c001h20xw42p017lm" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/AI/" rel="tag">AI</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Game/" rel="tag">Game</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-2021/2021-03-06-ansible" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2021/03/06/2021/2021-03-06-ansible/" class="article-date">
  <time datetime="2021-03-05T16:00:00.000Z" itemprop="datePublished">2021-03-06</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2021/03/06/2021/2021-03-06-ansible/">ansible笔记</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <p>ansible在平时运维的时候，是有机会使用到的。</p>
<h1 id="快速入门"><a href="#快速入门" class="headerlink" title="快速入门"></a>快速入门</h1><h2 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h2><ol>
<li>ubuntu</li>
</ol>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ sudo pip install paramiko PyYAML Jinja2 httplib2 six</span><br></pre></td></tr></table></figure>

<ol start="2">
<li>测试远程连击</li>
</ol>
<figure class="highlight bat"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">PS C:\Windows\system32&gt; Enter-PSSession <span class="number">127</span>.<span class="number">0</span>.<span class="number">0</span>.<span class="number">1</span> -Credential xxx.com\xxx</span><br><span class="line">[<span class="number">127</span>.<span class="number">0</span>.<span class="number">0</span>.<span class="number">1</span>]: PS C:\Users\xxx\Documents&gt; <span class="keyword">exit</span></span><br></pre></td></tr></table></figure>

<ol start="3">
<li>pywinrm</li>
</ol>
<figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> winrm</span><br><span class="line"></span><br><span class="line">s = winrm.Session(<span class="string">&#x27;MACHINEHOST&#x27;</span>, auth=(<span class="string">&#x27;username@domain&#x27;</span>, <span class="string">&#x27;password&#x27;</span>))</span><br><span class="line">r = s.run_cmd(<span class="string">&#x27;ipconfig&#x27;</span>, [<span class="string">&#x27;/all&#x27;</span>])</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span> r.status_code</span><br><span class="line"><span class="built_in">print</span> r.std_out</span><br></pre></td></tr></table></figure>

<figure class="highlight bat"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">root@xxxxx:/<span class="title">home</span>/<span class="title">xxxxx</span># <span class="title">ansible</span> 192.168.125.223 -<span class="title">m</span> <span class="title">win_ping</span></span></span><br><span class="line"><span class="function">192.168.125.223 | <span class="title">UNREACHABLE</span>! =&gt; &#123;</span></span><br><span class="line"><span class="function">    &quot;<span class="title">changed</span>&quot;: <span class="title">false</span>,</span></span><br><span class="line"><span class="function">    &quot;<span class="title">msg</span>&quot;: &quot;<span class="title">plaintext</span>: <span class="title">the</span> <span class="title">specified</span> <span class="title">credentials</span> <span class="title">were</span> <span class="title">rejected</span> <span class="title">by</span> <span class="title">the</span> <span class="title">server</span>&quot;,</span></span><br><span class="line"><span class="function">    &quot;<span class="title">unreachable</span>&quot;: <span class="title">true</span></span></span><br><span class="line"><span class="function">&#125;</span></span><br><span class="line"><span class="function"><span class="title">root</span>@<span class="title">xxxxx</span>:/<span class="title">home</span>/<span class="title">xxxxx</span># <span class="title">vim</span> /<span class="title">etc</span>/<span class="title">ansible</span>/<span class="title">hosts</span></span></span><br><span class="line"><span class="function"><span class="title">root</span>@<span class="title">xxxxx</span>:/<span class="title">home</span>/<span class="title">xxxxx</span># <span class="title">ansible</span> 192.168.125.223 -<span class="title">m</span> <span class="title">win_ping</span></span></span><br><span class="line"><span class="function">[<span class="title">WARNING</span>]:  * <span class="title">Failed</span> <span class="title">to</span> <span class="title">parse</span> /<span class="title">etc</span>/<span class="title">ansible</span>/<span class="title">hosts</span> <span class="title">with</span> <span class="title">yaml</span> <span class="title">plugin</span>: <span class="title">Syntax</span> <span class="title">Error</span> <span class="title">while</span> <span class="title">loading</span> <span class="title">YAML</span>.   <span class="title">did</span> <span class="title">not</span> <span class="title">find</span> <span class="title">expected</span></span></span><br><span class="line"><span class="function">&lt;<span class="title">document</span> <span class="title">start</span>&gt;  <span class="title">The</span> <span class="title">error</span> <span class="title">appears</span> <span class="title">to</span> <span class="title">be</span> <span class="title">in</span> &#x27;/<span class="title">etc</span>/<span class="title">ansible</span>/<span class="title">hosts</span>&#x27;: <span class="title">line</span> 46, <span class="title">column</span> 1, <span class="title">but</span> <span class="title">may</span> <span class="title">be</span> <span class="title">elsewhere</span> <span class="title">in</span> <span class="title">the</span> <span class="title">file</span> <span class="title">depending</span> <span class="title">on</span></span></span><br><span class="line"><span class="function"><span class="title">the</span> <span class="title">exact</span> <span class="title">syntax</span> <span class="title">problem</span>.  <span class="title">The</span> <span class="title">offending</span> <span class="title">line</span> <span class="title">appears</span> <span class="title">to</span> <span class="title">be</span>:  [<span class="title">windows</span>] 192.168.125.223 <span class="title">ansible_ssh_user</span>=&quot;<span class="title">admin</span>&quot;</span></span><br><span class="line"><span class="function"><span class="title">ansible_ssh_pass</span>=&quot;<span class="title">xxxxxx</span>&quot; <span class="title">ansible_ssh_port</span>=5985 <span class="title">ansible_connection</span>=&quot;<span class="title">winrm</span>&quot; <span class="title">ansible_winrm_server_cert_validation</span>=<span class="title">ignore</span> ^ <span class="title">here</span></span></span><br><span class="line"><span class="function">[<span class="title">WARNING</span>]:  * <span class="title">Failed</span> <span class="title">to</span> <span class="title">parse</span> /<span class="title">etc</span>/<span class="title">ansible</span>/<span class="title">hosts</span> <span class="title">with</span> <span class="title">ini</span> <span class="title">plugin</span>: <span class="title">Invalid</span> <span class="title">host</span> <span class="title">pattern</span> &#x27;<span class="title">ansible_winrm_transport</span>:&#x27; <span class="title">supplied</span>, <span class="title">ending</span></span></span><br><span class="line"><span class="function"><span class="title">in</span> &#x27;:&#x27; <span class="title">is</span> <span class="title">not</span> <span class="title">allowed</span>, <span class="title">this</span> <span class="title">character</span> <span class="title">is</span> <span class="title">reserved</span> <span class="title">to</span> <span class="title">provide</span> <span class="title">a</span> <span class="title">port</span>.</span></span><br><span class="line"><span class="function">[<span class="title">WARNING</span>]: <span class="title">Unable</span> <span class="title">to</span> <span class="title">parse</span> /<span class="title">etc</span>/<span class="title">ansible</span>/<span class="title">hosts</span> <span class="title">as</span> <span class="title">an</span> <span class="title">inventory</span> <span class="title">source</span></span></span><br><span class="line"><span class="function">[<span class="title">WARNING</span>]: <span class="title">No</span> <span class="title">inventory</span> <span class="title">was</span> <span class="title">parsed</span>, <span class="title">only</span> <span class="title">implicit</span> <span class="title">localhost</span> <span class="title">is</span> <span class="title">available</span></span></span><br><span class="line"><span class="function">[<span class="title">WARNING</span>]: <span class="title">provided</span> <span class="title">hosts</span> <span class="title">list</span> <span class="title">is</span> <span class="title">empty</span>, <span class="title">only</span> <span class="title">localhost</span> <span class="title">is</span> <span class="title">available</span>. <span class="title">Note</span> <span class="title">that</span> <span class="title">the</span> <span class="title">implicit</span> <span class="title">localhost</span> <span class="title">does</span> <span class="title">not</span> <span class="title">match</span> &#x27;<span class="title">all</span>&#x27;</span></span><br><span class="line"><span class="function">192.168.125.223 | <span class="title">UNREACHABLE</span>! =&gt; &#123;</span></span><br><span class="line"><span class="function">    &quot;<span class="title">changed</span>&quot;: <span class="title">false</span>,</span></span><br><span class="line"><span class="function">    &quot;<span class="title">msg</span>&quot;: &quot;<span class="title">plaintext</span>: <span class="title">the</span> <span class="title">specified</span> <span class="title">credentials</span> <span class="title">were</span> <span class="title">rejected</span> <span class="title">by</span> <span class="title">the</span> <span class="title">server</span>&quot;,</span></span><br><span class="line"><span class="function">    &quot;<span class="title">unreachable</span>&quot;: <span class="title">true</span></span></span><br><span class="line"><span class="function">&#125;</span></span><br></pre></td></tr></table></figure>

<p>快速配置的时候会出现这样的问题</p>
<figure class="highlight bat"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br></pre></td><td class="code"><pre><span class="line">PS C:\Windows\system32&gt; winrm quickconfig</span><br><span class="line">已在此计算机上运行 WinRM 服务。</span><br><span class="line">WSManFault</span><br><span class="line">    Message</span><br><span class="line">        ProviderFault</span><br><span class="line">            WSManFault</span><br><span class="line">                Message = 由于此计算机上的网络连接类型之一设置为公用，因此 WinRM 防火墙例外将不运行。 将网络连接类型更改为域或专用，然后再次尝试。</span><br><span class="line"></span><br><span class="line">错误编号: -<span class="number">2144108183</span> <span class="number">0</span>x80338169</span><br><span class="line">由于此计算机上的网络连接类型之一设置为公用，因此 WinRM 防火墙例外将不运行。 将网络连接类型更改为域或专用，然后再次尝试。</span><br><span class="line"></span><br><span class="line">PS C:\Windows\system32&gt; <span class="built_in">Set</span>-Item wsman:\localhost\Client\TrustedHosts -value <span class="number">192</span>.<span class="number">168</span>.<span class="number">125</span>.*</span><br><span class="line"></span><br><span class="line">WinRM 安全配置。</span><br><span class="line">此命令修改 WinRM 客户端的 TrustedHosts 列表。TrustedHosts</span><br><span class="line">列表中的计算机可能不会经过身份验证。该客户端可能会向这些计算机发送凭据信息。是否确实要修改此列表?</span><br><span class="line">[Y] 是(Y)  [N] 否(N)  [S] 暂停(S)  [?] 帮助 (默认值为“Y”): y</span><br><span class="line"></span><br><span class="line">通过命令查看当前情况：</span><br><span class="line"></span><br><span class="line">[<span class="number">192</span>.<span class="number">168</span>.<span class="number">125</span>.xxx]: PS C:\Users\HY\Documents&gt; winrm get winrm/config</span><br><span class="line">Config</span><br><span class="line">    MaxEnvelopeSizekb = <span class="number">500</span></span><br><span class="line">    MaxTimeoutms = <span class="number">60000</span></span><br><span class="line">    MaxBatchItems = <span class="number">32000</span></span><br><span class="line">    MaxProviderRequests = <span class="number">4294967295</span></span><br><span class="line">    Client</span><br><span class="line">        NetworkDelayms = <span class="number">5000</span></span><br><span class="line">        URLPrefix = wsman</span><br><span class="line">        AllowUnencrypted = false</span><br><span class="line">        Auth</span><br><span class="line">            Basic = true</span><br><span class="line">            Digest = true</span><br><span class="line">            Kerberos = true</span><br><span class="line">            Negotiate = true</span><br><span class="line">            Certificate = true</span><br><span class="line">            CredSSP = false</span><br><span class="line">        DefaultPorts</span><br><span class="line">            HTTP = <span class="number">5985</span></span><br><span class="line">            HTTPS = <span class="number">5986</span></span><br><span class="line">        TrustedHosts</span><br><span class="line">    Service</span><br><span class="line">        RootSDDL = O:NSG:BAD:P(A;;GA;;;BA)(A;;GR;;;IU)S:P(AU;FA;GA;;;WD)(AU;SA;GXGW;;;WD)</span><br><span class="line">        MaxConcurrentOperations = <span class="number">4294967295</span></span><br><span class="line">        MaxConcurrentOperationsPerUser = <span class="number">1500</span></span><br><span class="line">        EnumerationTimeoutms = <span class="number">240000</span></span><br><span class="line">        MaxConnections = <span class="number">300</span></span><br><span class="line">        MaxPacketRetrievalTimeSeconds = <span class="number">120</span></span><br><span class="line">        AllowUnencrypted = false</span><br><span class="line">        Auth</span><br><span class="line">            Basic = false</span><br><span class="line">            Kerberos = true</span><br><span class="line">            Negotiate = true</span><br><span class="line">            Certificate = false</span><br><span class="line">            CredSSP = false</span><br><span class="line">            CbtHardeningLevel = Relaxed</span><br><span class="line">        DefaultPorts</span><br><span class="line">            HTTP = <span class="number">5985</span></span><br><span class="line">            HTTPS = <span class="number">5986</span></span><br><span class="line">        IPv4Filter = *</span><br><span class="line">        IPv6Filter = *</span><br><span class="line">        EnableCompatibilityHttpListener = false</span><br><span class="line">        EnableCompatibilityHttpsListener = false</span><br><span class="line">        CertificateThumbprint</span><br><span class="line">        AllowRemoteAccess = true</span><br><span class="line">    Winrs</span><br><span class="line">        AllowRemoteShellAccess = true</span><br><span class="line">        IdleTimeout = <span class="number">7200000</span></span><br><span class="line">        MaxConcurrentUsers = <span class="number">2147483647</span></span><br><span class="line">        MaxShellRunTime = <span class="number">2147483647</span></span><br><span class="line">        MaxProcessesPerShell = <span class="number">2147483647</span></span><br><span class="line">        MaxMemoryPerShellMB = <span class="number">2147483647</span></span><br><span class="line">        MaxShellsPerUser = <span class="number">2147483647</span></span><br></pre></td></tr></table></figure>

<h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><ul>
<li>[1] <a target="_blank" rel="noopener" href="https://blog.51cto.com/7424593/2174156">Ansible批量远程管理Windows主机(部署与配置)</a></li>
<li>[2] <a target="_blank" rel="noopener" href="https://ansible-tran.readthedocs.io/en/latest/docs/developing_api.html">ansible中文手册</a></li>
<li>[3] <a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/99814357">验证失败的问题</a></li>
<li>[4] <a target="_blank" rel="noopener" href="https://blog.csdn.net/weixin_40943540/article/details/89344265">powershell远程连接</a></li>
</ul>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://example.com/2021/03/06/2021/2021-03-06-ansible/" data-id="ckrn3an7d001j20xw27ne53cx" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/%E8%BF%90%E7%BB%B4/" rel="tag">运维</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-2021/2021-02-23-帧同步和状态同步" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2021/01/23/2021/2021-02-23-%E5%B8%A7%E5%90%8C%E6%AD%A5%E5%92%8C%E7%8A%B6%E6%80%81%E5%90%8C%E6%AD%A5/" class="article-date">
  <time datetime="2021-01-22T16:00:00.000Z" itemprop="datePublished">2021-01-23</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2021/01/23/2021/2021-02-23-%E5%B8%A7%E5%90%8C%E6%AD%A5%E5%92%8C%E7%8A%B6%E6%80%81%E5%90%8C%E6%AD%A5/">帧同步和状态同步笔记</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <p>资料都来自于网络。</p>
<ul>
<li><a href="#%E5%89%8D%E8%A8%80">前言</a></li>
<li><a href="#%E7%BD%91%E7%BB%9C%E5%90%8C%E6%AD%A5%E6%A8%A1%E5%BC%8F%E7%9A%84%E6%BC%94%E5%8C%96%E5%8F%B2">网络同步模式的演化史</a><ul>
<li><a href="#%E6%A6%82%E5%BF%B5">概念</a></li>
<li><a href="#p2p%E6%A8%A1%E5%9E%8B">P2P模型</a></li>
<li><a href="#packet-server%E5%8C%85%E7%9A%84%E7%AE%80%E5%8D%95%E4%B8%AD%E7%BB%A7">Packet Server（包的简单中继）</a></li>
<li><a href="#client-server-quake-iiiiii">Client Server （Quake I/II/III）</a></li>
<li><a href="#%E5%93%8D%E5%BA%94%E6%80%A7%E5%92%8C%E9%A2%84%E5%88%A4">响应性和预判</a></li>
<li><a href="#%E5%BB%B6%E8%BF%9F%E8%A1%A5%E5%81%BF%E7%9A%84%E6%BD%9C%E5%9C%A8%E9%97%AE%E9%A2%98">延迟补偿的潜在问题</a></li>
<li><a href="#%E5%B7%A5%E7%A8%8B%E9%97%AE%E9%A2%98%E9%80%BB%E8%BE%91%E5%92%8C%E9%A2%84%E6%B5%8B%E4%BB%A3%E7%A0%81%E5%88%86%E7%A6%BB">工程问题：逻辑和预测代码分离</a></li>
<li><a href="#%E6%8F%92%E5%80%BC%E6%8E%A8%E5%AF%BC%E7%9A%84%E5%B1%80%E9%99%90%E6%80%A7">插值/推导的局限性</a></li>
<li><a href="#%E5%8E%8B%E7%BC%A9%E7%8A%B6%E6%80%81%E5%90%8C%E6%AD%A5%E5%86%97%E4%BD%99%E5%9B%BA%E5%AE%9A%E5%AD%97%E9%95%BF">压缩、状态同步冗余、固定字长</a></li>
</ul>
</li>
<li><a href="#%E5%B7%A5%E7%A8%8B%E5%AE%9E%E8%B7%B5">工程实践</a><ul>
<li><a href="#%E6%80%AA%E7%89%A9%E6%95%B0%E6%8D%AE%E5%90%8C%E6%AD%A5">怪物数据同步</a></li>
</ul>
</li>
<li><a href="#%E5%8F%82%E8%80%83">参考</a></li>
</ul>
<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>在制作网络游戏的时候，经常会讨论同步方式。同步这个话题就是让不同客户端的游戏表现同步。</p>
<p>王者荣耀是使用的帧同步(Lockstep)，有成功案例，后续才会有很多人想着跟进。</p>
<p>帧同步：服务器按照帧转换客户端的操作，其他客户端依赖这些信息在本地模拟表现。</p>
<p>状态同步：客户端操作的时候，只能将状态数据提交给服务器，服务器得到了通过运算将最终结果广播给全部客户端。</p>
<p>成功案例清单：</p>
<table>
<thead>
<tr>
<th align="left"></th>
<th align="left">帧同步</th>
<th align="left">状态同步</th>
</tr>
</thead>
<tbody><tr>
<td align="left">FPS</td>
<td align="left">doom</td>
<td align="left">CSGO、守望先锋、逆战、绝地求生</td>
</tr>
<tr>
<td align="left">MOBA</td>
<td align="left">王者荣耀、DOTA、英雄战境</td>
<td align="left">全民超神、LOL、DOTA2</td>
</tr>
<tr>
<td align="left">SPT</td>
<td align="left">NBAOline、街头篮球、FIFA</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">FGT,ACT</td>
<td align="left">街霸</td>
<td align="left">怪物猎人</td>
</tr>
<tr>
<td align="left">RTS</td>
<td align="left">星际争霸、魔兽争霸</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">MMO</td>
<td align="left">全民斗战神</td>
<td align="left">魔兽世界、轩辕传奇、天涯明月刀</td>
</tr>
<tr>
<td align="left">RAC</td>
<td align="left"></td>
<td align="left">QQ飞车</td>
</tr>
<tr>
<td align="left">其他</td>
<td align="left">街机、主机模拟器、刀塔传奇、剑与家园</td>
<td align="left">各种类型都有</td>
</tr>
</tbody></table>
<p>大量玩家参与的游戏只能使用状态同步。要求及时性高，</p>
<p>本文就记录一下同步的差异，各项资料都来自于baidu搜索的。其实在google上搜索，也没有看老外大量使用 state sync，frame sync，frame lock sync之类的文章。可能是我使用的词汇有问题。</p>
<h1 id="网络同步模式的演化史"><a href="#网络同步模式的演化史" class="headerlink" title="网络同步模式的演化史"></a>网络同步模式的演化史</h1><p>参考文档有：《The-DOOM-III-Network-Architecture》</p>
<ul>
<li><p>J.M.P. van Waveren</p>
</li>
<li><p>March 6th 2006</p>
</li>
</ul>
<h2 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h2><p>游戏需要再四个要素上做平衡：</p>
<p>一致性，响应性，带宽，延迟</p>
<p>FPS实体列表：</p>
<p>玩家，怪物，导弹，门。</p>
<p>参与者去管理和维护自由的那份拷贝，一种实现是通过施加一致性的逻辑推动所有的状态去同步地更新，另一种实现是随着时间的流逝不断地比较和发送最小的状态变化和差异。</p>
<h2 id="P2P模型"><a href="#P2P模型" class="headerlink" title="P2P模型"></a>P2P模型</h2><p>Doom（1994）的网络模型是完全同步的P2P系统。每秒对玩家动作（move/turn/use/fire, etc.) 采样 35 次 (得到一个 tick command) 并发送给其他所有玩家，每个玩家都接受来自所有玩家的 tick command，当某个玩家收到所有其他玩家的下一帧 tick command 后，该玩家的本地游戏状态推进到下一帧。这样的后果是全局性的延迟 (每个玩家从做出动作到收到反馈的响应时间) 由<strong>最慢网络</strong>连接的玩家决定。</p>
<p>存在问题清单：</p>
<ol>
<li>所有玩家都需要主动维护完美的状态同步，由于硬件不同(有时甚至是未初始化的变量)等引入的不一致，会让每个参与者细微的不同被累积下来，导致参与者之间显著的视觉和逻辑的差异。这种不一致的引入很难查，因为只有当它们累积起来才会有明显的效果，而等感觉到差异时，真正的问题已经发生很久了。</li>
<li>完全同步的网络无法跨平台。不同的硬件上，由不同编译器生成的汇编指令有时会产生轻微不同的行为 (浮点指令尤甚)。</li>
<li>随着玩家数量增长，延迟会迅速变得难以接受。而且只要有一个玩家的网络有波动，会影响到所有人的体验。<br>随着玩家数量增长，带宽需求会指数性地同步增长。</li>
<li>同步网络由于只发送 tick command，所有玩家必须同时启动游戏 (来保证游戏状态的一致性) 无法做到随时的加入和退出。</li>
<li>由于玩家本地维护了所有的状态，方便了作弊的实现。</li>
</ol>
<h2 id="Packet-Server（包的简单中继）"><a href="#Packet-Server（包的简单中继）" class="headerlink" title="Packet Server（包的简单中继）"></a>Packet Server（包的简单中继）</h2><p>P2P模型上增加Packet Server，将接受到的tick command转发，这样减少了客户端直接的链接。能解决某个玩家慢的问题。</p>
<h2 id="Client-Server-（Quake-I-II-III）"><a href="#Client-Server-（Quake-I-II-III）" class="headerlink" title="Client Server （Quake I/II/III）"></a>Client Server （Quake I/II/III）</h2><p>Quake I/II/III 实现了比较典型的 C/S 架构 (1996)，这个模型中服务器负责所有的逻辑判断，客户端本质上只是一个渲染终端。玩家把自己的操作和输入发送给服务器，收到一个实体列表用于渲染。服务器把压缩后的快照发给客户端 (10-20Hz) 客户端使用这些快照来插值或推导出平滑连贯的体验 (interpolates between, or extrapolates from the last two snapshots)。</p>
<p>在一般情况下(比如在古代的引擎Quake 1中)，客户端收集到用户命令后发送给服务器，此后就在等待服务器返回新的游戏状态。这是很笨的。在Quake 3中，客户端不会傻等，而会预测可能的游戏状态，其实预测状态所用的代码跟服务器端的代码是一样的，所以服务器端的状态和客户端的状态往往是一致的。如果确实不一致，则“服务器为准原则”将生效。</p>
<p>“Quake III Arena 网络协议规范(非官方)”</p>
<h2 id="响应性和预判"><a href="#响应性和预判" class="headerlink" title="响应性和预判"></a>响应性和预判</h2><p>这个模型同样有响应性问题，从输入的采样和发送到屏幕反馈同样需要一个 roundtrip 延时。为了克服延时客户端预测了玩家的下一步行动 (在之前的 blog中有提到)。玩家的输入在发出去的同时，本地立刻处理，而环境状态做了上文说到的 interpolate/extrapolate，也就是说玩家看到的自身是 (可预计的) 操作结果，而其他人是过去的状态。(这一点与魔兽世界是一致的) 这个 C/S 架构是异步的。对任何一个玩家而言，服务器的全局模拟落后于该玩家在本地的实际操作快照，而环境的状态同步更是落后于全局模拟。</p>
<p>这个模型允许中途加入和退出 (除了做 server 的玩家，如果不是 dedicated 的话)。由于玩家的判断基于的是其他玩家过去的状态，实际的击中检测发生在晚些时候的服务器上，在延时较高的情况下，玩家需要不断考虑延时状况并打提前量才能在未来的实际判断中击中对方。</p>
<h2 id="延迟补偿的潜在问题"><a href="#延迟补偿的潜在问题" class="headerlink" title="延迟补偿的潜在问题"></a>延迟补偿的潜在问题</h2><p>半条命在这个基础上引入了一种特定的延迟补偿 (lag compensation)，当玩家向某个目标 (若干毫秒前的状态) 射击时，做实际检测的服务器会采用该目标若干毫秒前的状态来检验是否击中。这么做需要服务器把之前一小段时间的状态持续地保存下来，这样不仅增加了实现复杂度，而且导致了某种程度的不一致性。延时高的玩家反而更容易因为补偿获得更有利的判断，严重影响游戏体验 (实例见这里第六页末尾，值得一读)。这种补偿只能对目标的位置回滚，而所有其他环境状态的改变却已无法倒退，这也会影响实际的体验。</p>
<h2 id="工程问题：逻辑和预测代码分离"><a href="#工程问题：逻辑和预测代码分离" class="headerlink" title="工程问题：逻辑和预测代码分离"></a>工程问题：逻辑和预测代码分离</h2><p>Q3 里服务器上跑的逻辑代码 (“game code”) 跟客户端跑的渲染和预测代码 (“client game code”) 实现在物理上不同的模块里，但却需要对彼此的内部细节非常清楚 (才能保证预测和实际行为的一致性)。这个强耦合使得扩展游戏变得很困难，这也是难以实现单人游戏模式的原因之一。有时使用 Q3 引擎的游戏得为多人模式和单人模式发布两个不同的 exe，其中单人模式直接使用 game code 来简化逻辑流程。</p>
<h2 id="插值-推导的局限性"><a href="#插值-推导的局限性" class="headerlink" title="插值/推导的局限性"></a>插值/推导的局限性</h2><p>由于快照的接收频率往往低于实际渲染的帧速，就需要上文提到的 interpolate/extrapolate，考虑物理模拟和交互的话，(为了跟服务器逻辑一致) 推导会增加额外的实现复杂度。这些插值对位置数据很有效，但其他一些状态很难插值，有时性能也是问题，比如四元数的 slerp 就挺费的 (上一篇末尾提到了相关的优化)</p>
<h2 id="压缩、状态同步冗余、固定字长"><a href="#压缩、状态同步冗余、固定字长" class="headerlink" title="压缩、状态同步冗余、固定字长"></a>压缩、状态同步冗余、固定字长</h2><p>Quake III 里只有在 PVS 内的实体才会被同步状态，而且被同步的是压缩后的与上一次同步比较的差值 (delta compressed relative to the entity states from a previous snapshot) 这导致的结果是如果一个物体频繁进出 PVS 就没法做 delta 比较，总是发送完整状态，会导致不少冗余的同步量。</p>
<blockquote>
<p>为了提高网络通讯速度，降低带宽，Quake 3中采用了压缩的技术。这并不是指用一些压缩算法来直接压缩数据。而是指，在传送游戏状态数据时，只传送改变了的游戏状态，而不是全部发送过来。一般来说，这个叫做Delta技术。</p>
</blockquote>
<p>“Quake III Arena 网络协议规范(非官方)”<br>出于简化，Q3 使用了固定长度的同步结构，导致不少字段被不同的功能各种复用，一晦涩复杂度就上去了。</p>
<h1 id="工程实践"><a href="#工程实践" class="headerlink" title="工程实践"></a>工程实践</h1><h2 id="怪物数据同步"><a href="#怪物数据同步" class="headerlink" title="怪物数据同步"></a>怪物数据同步</h2><p>将服务器计算的怪物寻路点一次性全部发送给客户端；</p>
<p>定时同步服务器已经行走到什么地方了；</p>
<p>在关键位置需要强制同步一次服务器位置给客户端。</p>
<h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><ul>
<li>[1] <a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/104932624">帧同步和状态同步该怎么选（上）</a></li>
<li>[2] <a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/105826545">帧同步和状态同步该怎么选（下）</a></li>
<li>[3] <a target="_blank" rel="noopener" href="https://zentia.github.io/2019/04/22/frame-sync/">帧锁定同步.按帧同步.状态同步</a></li>
<li>[4] <a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/38468615">帧同步联机战斗（预测，快照，回滚）</a></li>
<li>[5] <a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/21705866">Doom/Quake I/II/III网络模型演化</a></li>
<li>[6] <a target="_blank" rel="noopener" href="https://github.com/id-Software/DOOM">Doom源码</a></li>
<li>[7] <a target="_blank" rel="noopener" href="https://fabiensanglard.net/doom3_documentation/The-DOOM-III-Network-Architecture.pdf">The-DOOM-III-Network-Architecture</a></li>
<li>[8] <a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/130702310">细谈网络同步在游戏历史中的发展变化</a></li>
</ul>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://example.com/2021/01/23/2021/2021-02-23-%E5%B8%A7%E5%90%8C%E6%AD%A5%E5%92%8C%E7%8A%B6%E6%80%81%E5%90%8C%E6%AD%A5/" data-id="ckrn3an7b001d20xw2l371riq" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Game/" rel="tag">Game</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-2021/2021-01-22-线性代数" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2021/01/22/2021/2021-01-22-%E7%BA%BF%E6%80%A7%E4%BB%A3%E6%95%B0/" class="article-date">
  <time datetime="2021-01-21T16:00:00.000Z" itemprop="datePublished">2021-01-22</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2021/01/22/2021/2021-01-22-%E7%BA%BF%E6%80%A7%E4%BB%A3%E6%95%B0/">线性代数笔记</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <ul>
<li><a href="#1-%E8%A1%8C%E5%88%97%E5%BC%8F">1. 行列式</a><ul>
<li><a href="#%E4%BA%8C%E9%98%B6%E4%B8%89%E9%98%B6%E8%A1%8C%E5%88%97%E5%BC%8F">二阶、三阶行列式</a><ul>
<li><a href="#%E6%8E%92%E5%88%97">排列</a></li>
<li><a href="#%E5%AF%B9%E6%8D%A2">对换</a></li>
</ul>
</li>
<li><a href="#n%E9%98%B6%E8%A1%8C%E5%88%97%E5%BC%8F%E7%9A%84%E5%AE%9A%E4%B9%89">n阶行列式的定义</a></li>
<li><a href="#%E8%A1%8C%E5%88%97%E5%BC%8F%E6%80%A7%E8%B4%A8">行列式性质</a></li>
<li><a href="#%E8%A1%8C%E5%88%97%E5%BC%8F%E6%8C%89%E8%A1%8C%E5%B1%95%E5%BC%80">行列式按行展开</a><ul>
<li><a href="#%E6%8C%89%E8%A1%8C%E5%B1%95%E5%BC%80">按行展开</a></li>
<li><a href="#%E6%8B%89%E6%99%AE%E6%8B%89%E6%96%AF%E5%AE%9A%E7%90%86">拉普拉斯定理</a></li>
<li><a href="#%E8%A1%8C%E5%88%97%E5%BC%8F%E7%9B%B8%E4%B9%98">行列式相乘</a></li>
</ul>
</li>
<li><a href="#%E8%A1%8C%E5%88%97%E5%BC%8F%E7%9A%84%E8%AE%A1%E7%AE%97%E4%B8%80">行列式的计算（一）</a></li>
<li><a href="#%E8%A1%8C%E5%88%97%E5%BC%8F%E7%9A%84%E8%AE%A1%E7%AE%97%E4%BA%8C">行列式的计算（二）</a><ul>
<li><a href="#%E4%BE%8B6%E5%8A%A0%E8%BE%B9%E6%B3%95%E8%A7%A3%E6%96%B9%E7%A8%8B">例6：加边法解方程</a></li>
<li><a href="#%E4%BE%8B7%E8%8C%83%E5%BE%B7%E8%92%99%E5%BE%B7%E8%A1%8C%E5%88%97%E5%BC%8F">例7：范德蒙德行列式</a></li>
<li><a href="#%E4%BE%8B8%E5%8F%8D%E5%AF%B9%E7%A7%B0%E8%A1%8C%E5%88%97%E5%BC%8F%E5%AF%B9%E7%A7%B0%E8%A1%8C%E5%88%97%E5%BC%8F">例8：反对称行列式、对称行列式</a></li>
</ul>
</li>
<li><a href="#%E5%85%8B%E8%8E%B1%E5%A7%86%E6%B3%95%E5%88%99-cramers-rule">克莱姆法则 Cramer’s rule</a></li>
</ul>
</li>
<li><a href="#2-%E7%9F%A9%E9%98%B5-matrix">2. 矩阵 Matrix</a><ul>
<li><a href="#%E7%9F%A9%E9%98%B5%E6%A6%82%E5%BF%B5">矩阵概念</a></li>
<li><a href="#%E9%9B%B6%E7%9F%A9%E9%98%B5">零矩阵</a></li>
<li><a href="#%E8%B4%9F%E7%9F%A9%E9%98%B5">负矩阵</a></li>
<li><a href="#%E5%8D%95%E4%BD%8D%E7%9F%A9%E9%98%B5">单位矩阵</a></li>
<li><a href="#%E7%9F%A9%E9%98%B5%E8%BF%90%E7%AE%97%E4%B8%80">矩阵运算（一）</a><ul>
<li><a href="#%E5%8A%A0%E6%B3%95">加法</a></li>
<li><a href="#%E5%87%8F%E6%B3%95">减法</a></li>
<li><a href="#%E6%95%B0%E4%B9%98">数乘</a></li>
<li><a href="#%E6%8F%90%E5%85%AC%E5%9B%A0%E5%AD%90">提公因子</a></li>
<li><a href="#%E7%9F%A9%E9%98%B5%E7%9A%84%E4%B9%98%E6%B3%95%E9%9D%9E%E5%B8%B8%E9%87%8D%E8%A6%81">矩阵的乘法（非常重要）</a><ul>
<li><a href="#%E7%9F%A9%E9%98%B5%E4%B9%98%E6%B3%95%E9%80%9F%E8%AE%B0">矩阵乘法速记</a></li>
<li><a href="#%E4%B9%98%E6%B3%95%E4%B8%8D%E6%BB%A1%E8%B6%B3%E7%9A%84%E4%B8%89%E8%A7%84%E5%BE%8B">乘法不满足的三规律</a></li>
<li><a href="#%E4%B8%8E%E9%9B%B6%E7%9F%A9%E9%98%B5%E7%9B%B8%E4%B9%98">与零矩阵相乘</a></li>
<li><a href="#%E4%B8%8Ee%E5%8D%95%E4%BD%8D%E7%9F%A9%E9%98%B5%E7%9B%B8%E4%B9%98">与E（单位矩阵）相乘</a></li>
<li><a href="#%E7%BB%93%E5%90%88%E5%BE%8B%E5%88%86%E9%85%8D%E5%BE%8B">结合律分配律</a></li>
<li><a href="#%E4%BE%8B6%E5%8F%AF%E4%BA%A4%E6%8D%A2">例6：可交换</a></li>
<li><a href="#%E4%BE%8B7">例7：</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#%E7%9F%A9%E9%98%B5%E8%BF%90%E7%AE%97%E4%BA%8C">矩阵运算（二）</a><ul>
<li><a href="#%E7%9F%A9%E9%98%B5%E5%B9%82%E8%BF%90%E7%AE%97">矩阵幂运算</a></li>
<li><a href="#%E8%BD%AC%E7%BD%AE">转置</a></li>
</ul>
</li>
<li><a href="#%E7%89%B9%E6%AE%8A%E7%9F%A9%E9%98%B5">特殊矩阵</a><ul>
<li><a href="#%E6%95%B0%E9%87%8F%E7%9F%A9%E9%98%B5">数量矩阵</a></li>
<li><a href="#%E5%AF%B9%E8%A7%92%E5%BD%A2%E7%9F%A9%E9%98%B5">对角形矩阵</a></li>
<li><a href="#%E4%B8%89%E8%A7%92%E5%BD%A2%E7%9F%A9%E9%98%B5">三角形矩阵</a></li>
<li><a href="#%E5%AF%B9%E7%A7%B0%E7%9F%A9%E9%98%B5">对称矩阵</a></li>
</ul>
</li>
<li><a href="#%E9%80%86%E7%9F%A9%E9%98%B5%E4%B8%80">逆矩阵（一）</a><ul>
<li><a href="#%E6%96%B9%E9%98%B5%E7%9A%84%E8%A1%8C%E5%88%97%E5%BC%8F">方阵的行列式</a></li>
<li><a href="#%E4%BC%B4%E9%9A%8F%E7%9F%A9%E9%98%B5-a">伴随矩阵 $A^*$</a></li>
</ul>
</li>
<li><a href="#%E9%80%86%E7%9F%A9%E9%98%B5%E4%BA%8C">逆矩阵（二）</a><ul>
<li><a href="#%E4%BC%B4%E9%9A%8F%E7%9F%A9%E9%98%B5%E6%B3%95">伴随矩阵法</a></li>
<li><a href="#%E5%88%9D%E7%AD%89%E5%8F%98%E6%8D%A2%E6%B3%95%E8%80%83%E8%AF%95%E7%9A%84%E6%97%B6%E5%80%99%E5%B8%B8%E7%94%A8%E6%B3%95">初等变换法（考试的时候常用法）</a></li>
</ul>
</li>
<li><a href="#%E5%88%86%E5%9D%97%E7%9F%A9%E9%98%B5">分块矩阵</a></li>
<li><a href="#%E5%88%9D%E7%AD%89%E5%8F%98%E6%8D%A2%E4%B8%80">初等变换（一）</a></li>
<li><a href="#%E5%88%9D%E7%AD%89%E5%8F%98%E6%8D%A2%E4%BA%8C">初等变换（二）</a></li>
<li><a href="#%E5%88%9D%E7%AD%89%E5%8F%98%E6%8D%A2%E4%B8%89">初等变换（三）</a></li>
<li><a href="#%E7%9F%A9%E9%98%B5%E7%9A%84%E7%A7%A9%E4%B8%80">矩阵的秩（一）</a></li>
<li><a href="#%E7%9F%A9%E9%98%B5%E7%9A%84%E7%A7%A9%E4%BA%8C">矩阵的秩（二）</a></li>
</ul>
</li>
<li><a href="#%E5%8F%82%E8%80%83">参考</a></li>
</ul>
<p>参考资料《空间解析几何与线性代数》 ISBN 7-11-14572-0，机械工业出版社。</p>
<p>(╯‵□′)╯︵┻━┻</p>
<p>丛书清单：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">高等工科数学系列课程教材</span><br><span class="line">工科数学分析教程</span><br><span class="line">空间解析几何与线性代数</span><br><span class="line">概率论与数理统计</span><br><span class="line">复变函数论与运算微积分</span><br><span class="line">计算技术与程序设计</span><br><span class="line">最优化方法</span><br><span class="line">数学物理方程</span><br></pre></td></tr></table></figure>

<p>线性方程组是线性代数的基础。</p>
<p>搞清楚三个概念</p>
<ol>
<li>行列式概念的形成</li>
<li>行列式的基本性质及计算方法</li>
<li>利用行列式求解线性方程组</li>
</ol>
<h1 id="1-行列式"><a href="#1-行列式" class="headerlink" title="1. 行列式"></a>1. 行列式</h1><h2 id="二阶、三阶行列式"><a href="#二阶、三阶行列式" class="headerlink" title="二阶、三阶行列式"></a>二阶、三阶行列式</h2><p>先来解含两个未知量$x_{1},x_{2}$的线性方程组</p>
<p>$$\begin{cases}<br>a_{11}x_{1}+a_{12}x_{2}=b_{1}\<br>a_{21}x_{1}+a_{22}x_{2}=b_{2}<br>\end{cases} \tag{1.1.1}$$</p>
<p>如果想消元$x_{1}$得到$x_{2}$，就将第一行都乘以$a_{21}$，第二行乘以$a_{11}$</p>
<p>$$\begin{cases}<br>a_{11}a_{21}x_{1}+a_{12}a_{21}x_{2}=a_{21}b_{1}\<br>a_{11}a_{21}x_{1}+a_{11}a_{22}x_{2}=a_{11}b_{2}<br>\end{cases} \tag{1.1.2}$$</p>
<p>两个式子相减就能得出只有$x_{2}$的一个式子</p>
<p>$$<br>(a_{12}a_{21}-a_{11}a_{22})x_{2} = a_{21}b_{1}-a_{11}b_{2}\<br>x_{2} = \frac{a_{21}b_{1}-a_{11}b_{2}}<br>{a_{12}a_{21}-a_{11}a_{22}}<br>$$</p>
<p>求$x_{1}$也一样</p>
<p>$$\begin{cases}<br>a_{22}a_{11}x_{1}+a_{22}a_{12}x_{2}=a_{22}b_{1}\<br>a_{12}a_{21}x_{1}+a_{22}a_{12}x_{2}=a_{12}b_{2}<br>\end{cases} \<br>x_{1}=\frac{a_{22}b_{1}-a_{12}b_{2}}{a_{22}a_{11}-a_{12}a_{21}}<br>\tag{1.1.3}$$</p>
<p>现在开始定义一个新的运算式子</p>
<p>$$<br>x_{1}=\frac{b_{1}a_{22}-a_{12}b_{2}}<br>{a_{11}a_{22}-a_{12}a_{21}}=<br>\frac{<br>\left|\begin{matrix}<br>a_{11}&amp;b_{1}\<br>a_{21}&amp;b_{2}<br>\end{matrix}\right|<br>}{<br>\left|\begin{matrix}<br>a_{11}&amp;a_{12}\<br>a_{21}&amp;a_{22}<br>\end{matrix}\right|}<br>$$</p>
<p>$$<br>x_{2}=\frac{a_{21}b_{1}-a_{11}b_{2}}{a_{12}a_{21}-a_{11}a_{22}}<br>$$</p>
<p>定义运算，二阶行列式的定义</p>
<p>$$<br>\left|\begin{matrix}<br>a_{11}&amp;a_{12}\<br>a_{21}&amp;a_{22}<br>\end{matrix}\right|=a_{11}a_{22} - a_{21}a_{12}<br>$$</p>
<p>主对角线\</p>
<p>次对角线/</p>
<p>三阶行列式展开。三个正向，三个负向，六个项目。</p>
<p>$$<br>\left|\begin{matrix}<br>1&amp;2&amp;3\<br>4&amp;5&amp;6\<br>7&amp;8&amp;9<br>\end{matrix}\right|=1<em>5</em>9 + 2<em>6</em>7 + 4<em>8</em>3 - 3<em>5</em>7 - 4<em>2</em>9 - 6<em>8</em>1<br>$$</p>
<p>这个画出来就是个环绕的方式。</p>
<h3 id="排列"><a href="#排列" class="headerlink" title="排列"></a>排列</h3><p>由1,2,…,n组成的一个有序数组，叫做n级排列。</p>
<p>n级排列 = n(n-1) … 3<em>2</em>1 = n!</p>
<p>逆序：大数排在小数前面。符号计为N</p>
<p>逆序数：从第一个开始数逆序总数</p>
<p>$$N(4213)=3+1=4$$</p>
<p>4后面有3个比它小的数，2后面只有1个比它小的数，1后面没有比它小的数，3后面也没有比它小的数。所以逆序数为4。</p>
<p>逆序数数字为奇数，就是奇排列，反之就是偶排列。</p>
<p>标准排列（自然排列）</p>
<p>$$N(123…N)=0$$</p>
<p>$$N(n(n-1)…321)=n-1+n-2…+2+1=\frac{n(n-1)}{2}$$</p>
<p>差数求和公式。</p>
<h3 id="对换"><a href="#对换" class="headerlink" title="对换"></a>对换</h3><p>概念：交换两个数。</p>
<p>N(5 4 2 1 3)</p>
<p>将1，3对换，就变成了</p>
<p>N(5 4 2 1 3)</p>
<p>一个逆序数做一次对换，奇偶性质会变换一次。交换奇数次，奇偶性改变；交换偶数次奇偶性不变。</p>
<p>定理：n级排列中，奇排列、偶排列各占$\frac{n!}{2}$</p>
<h2 id="n阶行列式的定义"><a href="#n阶行列式的定义" class="headerlink" title="n阶行列式的定义"></a>n阶行列式的定义</h2><p>如果划线，4阶行列式=24根线。</p>
<p>先引入三阶行列式：</p>
<p>$$<br>\left|\begin{matrix}<br>a_{11}&amp;a_{12}&amp;a_{13}\<br>a_{21}&amp;a_{22}&amp;a_{23}\<br>a_{31}&amp;a_{32}&amp;a_{33}<br>\end{matrix}\right|= a_{11}a_{22}a_{33}+a_{12}a_{23}a_{31}+a_{13}a_{21}+a_{32}<br>-a_{13}a_{22}a_{31}-a_{12}a_{21}a_{33}-a_{11}a_{23}a_{32}<br>$$</p>
<p>行标=标准排列 1 2 3</p>
<p>列表=其实就是取了排列的所有可能。从不同行，不同列取出3个元素相乘。将排列的偶排列数-奇排列的数字。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">123  0</span><br><span class="line">231  2    偶排列+</span><br><span class="line">312  2</span><br><span class="line">--------</span><br><span class="line">321  3</span><br><span class="line">213  1    奇排列-</span><br><span class="line">132  1</span><br></pre></td></tr></table></figure>

<p>所以n阶行列式展开，就能通过<strong>按行展开</strong>定义。</p>
<p>$$<br>\left|\begin{matrix}<br>a_{11}&amp;a{12}&amp;…&amp;a_{1n}\<br>a_{11}&amp;a{12}&amp;…&amp;a_{1n}\<br>…&amp;…&amp;…&amp;\<br>a_{n1}&amp;a{n2}&amp;…&amp;a_{nn}<br>\end{matrix}\right|=\sum_J^I a_{1j_{1}}a_{2j_{2}} … a_{nj_{n}}\<br>J=j_{1},j_{2}…j_{n}\<br>I=N(i_{1},i_{2}…i_{n})\<br>D=|a_{ij}|<br>$$</p>
<p>当行列式大量都是为0的情况下计算展开，能直接计算出来它的值。</p>
<p>其他23个行列式由于都会算到和0相乘，所以都会变成零，可以不去管它们。最终只有这个式子。只需要对2341做奇偶性排列的判断，之后就能确定最终数值。</p>
<p>$$<br>\left|\begin{matrix}<br>0 &amp;2&amp;0&amp;0\<br>0&amp;0&amp;3&amp;0\<br>0&amp;0&amp;0&amp;4\<br>1&amp;0&amp;0&amp;0<br>\end{matrix}\right|= (-1)^{N(2341)}2<em>3</em>4<em>1=-1</em>24<br>$$</p>
<p><em>下三角行列式</em> 主对角线元素相乘。就是主对角线相乘</p>
<p><em>上三行列式</em> 次对角线元素相乘。</p>
<h2 id="行列式性质"><a href="#行列式性质" class="headerlink" title="行列式性质"></a>行列式性质</h2><p>行列式的转置就是行转成列，列传成行。转两次之后就等于自身。转置值不变。</p>
<p>$$D^T=D$$</p>
<blockquote>
<p>性质1：行列式转置之后，对于行成立的性质，对转置之后的列也成立。</p>
</blockquote>
<blockquote>
<p>性质2：一个行列式的两个行做交换之后得到的行列式，符号相反。<br>推论：行列式如果有两行（列）完全相同，行列式是为0</p>
</blockquote>
<p>证明：原理就是列不变，行标变了一次，和上一章节里面的逆数中的定理，排列里面数字交换一次，奇偶性取反。行列式展开的每一项都会是如此，所以符号会取反。</p>
<blockquote>
<p>性质4：某行有公因子，可以提出去到行列式外面。<br>变成了标量乘法。</p>
</blockquote>
<blockquote>
<p>性质5：两列行列式对应程比例，D=0<br>基于4，先将倍率提取到外面，这样就有两行相同的。</p>
</blockquote>
<blockquote>
<p>性质6：是和的那一行分开，<strong>其他行保持不变</strong>，拆开之后相加。</p>
</blockquote>
<p>这个很容易弄错。</p>
<blockquote>
<p>性质7：行列式某行乘以一个数，加到另一行上去，行列式的值不变。<br>其实就是先使用性质6，分离出两个行列式；用提取倍率出去，而且里面两行相同行列式就为0了。</p>
</blockquote>
<p>性质7非常非常重要，出错的人特别多。</p>
<p>例题推算</p>
<p>一般纯数字的行列式都是被转换成一个上三角行列式。</p>
<p>消除掉行列式的值，其实就是将行上的值乘上数字，加到对应行上去，这样消掉对应那个位置的数字。<a target="_blank" rel="noopener" href="https://www.bilibili.com/video/BV1aW411Q7x1?p=3">行列式性质53”59’</a></p>
<p>做题，先将有数字1的行要交换上去。先按照规范（用一列消第二列，然后用第二列消第三列，一次来类推，在处理第三行的时候，第二行不再参与运算—原因来自于这样解题会无法结束。其实这个解体类似于解开魔方）来解体，这样反而简单。</p>
<p>第七条定理用得非常频繁，也非常容易让人用的时候糊涂。最好看一下原视频的论述，非常精彩。</p>
<h2 id="行列式按行展开"><a href="#行列式按行展开" class="headerlink" title="行列式按行展开"></a>行列式按行展开</h2><blockquote>
<p>行列式按行展开<br>异乘变零定理<br>行列式相乘定理</p>
</blockquote>
<p>余子式</p>
<p>找到行列式中的某个数字，将它所在的行、列都删除剩下的元素组成的行列式。余子式一般都使用 $M_{12}$ 来表示。</p>
<p>代数余子式</p>
<p>在n阶行列式中，把元素aₒₑ所在的第o行和第e列划去后，留下来的n-1阶行列式叫做元素aₒₑi的余子式，记作Mₒₑ，将余子式Mₒₑ再乘以-1的o+e次幂记为Aₒₑ，Aₒₑ叫做元素aₒₑ的代数余子式。代数余子式的符号是 $A_{12}$。</p>
<h3 id="按行展开"><a href="#按行展开" class="headerlink" title="按行展开"></a>按行展开</h3><blockquote>
<p>行列式按（列）展开： 行列式的值=某个元素值乘以的自己的代数余子式。</p>
</blockquote>
<p>好处可以降低阶数。</p>
<p>选择0比较多的行或列展开。</p>
<blockquote>
<p>异乘变零：某行元素与另一行元素的代数余子式乘积之和=0</p>
</blockquote>
<h3 id="拉普拉斯定理"><a href="#拉普拉斯定理" class="headerlink" title="拉普拉斯定理"></a>拉普拉斯定理</h3><p>k阶子式。</p>
<p>举例子二阶子式</p>
<p>取两行，两列两行两列相交的数字取出来，就是二阶子式。</p>
<p>去掉所选取的行列的数字，组成的行列式就是二阶余子式。</p>
<p>代数余子式，就是余子式前面加上一个符号，符号决定于，所取行列来决定余子式。</p>
<p>取定k行，由k行元素组成的所有k阶子式与余子式乘积之和=D。</p>
<p>当有成片的0出现的时候，使用这个展开式，将会很快能计算出结果。</p>
<p>$$<br>\left|<br>\begin{matrix}<br>  1&amp;2&amp;0&amp;0&amp;0\<br>  3&amp;4&amp;0&amp;0&amp;0\<br>  1&amp;2&amp;3&amp;4&amp;5\<br>  1&amp;1&amp;1&amp;1&amp;1\<br>  8&amp;8&amp;8&amp;3&amp;1<br>\end{matrix}<br>\right|=<br>\left|<br>\begin{matrix}<br>  1&amp;2\<br>  3&amp;4<br>\end{matrix}<br>\right|<br>(-1)^{1+2+1+2}<br>\left|<br>\begin{matrix}<br>  3&amp;4&amp;5\<br>  1&amp;1&amp;1\<br>  8&amp;3&amp;1<br>\end{matrix}<br>\right|<br>$$</p>
<h3 id="行列式相乘"><a href="#行列式相乘" class="headerlink" title="行列式相乘"></a>行列式相乘</h3><p>只有同阶行列式才能相乘，如果非同阶的行列式，可以将他们的值算出来，直接相乘。如果是为了计算行列式的最终值，其实用的不算太多。</p>
<p>$$<br>\left|<br>\begin{matrix}<br>  1&amp;1&amp;1\<br>  2&amp;0&amp;0\<br>  0&amp;0&amp;3<br>\end{matrix}<br>\right|<br>\times<br>\left|<br>\begin{matrix}<br>  1&amp;2&amp;3\<br>  1&amp;3&amp;2\<br>  3&amp;2&amp;1<br>\end{matrix}<br>\right|=<br>\left|<br>\begin{matrix}<br>  5&amp;7&amp;6\<br>  2&amp;4&amp;6\<br>  9&amp;6&amp;3<br>\end{matrix}<br>\right|<br>$$</p>
<p>前面式子的行$\times$后面式子的列相乘累加。</p>
<h2 id="行列式的计算（一）"><a href="#行列式的计算（一）" class="headerlink" title="行列式的计算（一）"></a>行列式的计算（一）</h2><p>考试的时候，基本上都是在考计算行列式的结果，需要利用之前学习的行列式性质，定理来展开。</p>
<ol>
<li>如果是纯数字的行列式，先老老实实的化成上三角行列式。</li>
</ol>
<p>$$<br>\left|\begin{matrix}<br>  2&amp;1&amp;7&amp;-1\<br>  -1&amp;2&amp;4&amp;3\<br>  2&amp;1&amp;0&amp;-1\<br>  3&amp;2&amp;2&amp;1<br>\end{matrix}<br>\right|=\left|\begin{matrix}<br>  2&amp;1&amp;7&amp;-1\<br>  0&amp;2&amp;4&amp;3\<br>  0&amp;0&amp;…&amp;…\<br>  0&amp;0&amp;0&amp;…<br>\end{matrix}<br>\right|<br>$$</p>
<p>消元套路是使用 <a href="###%E8%A1%8C%E5%88%97%E5%BC%8F%E6%80%A7%E8%B4%A8">行列式性质</a>里面第7号特性。先将$a_{21}$位置消元。如同瀑布一样，使用第二行开始将第三行的第二个元素消元。</p>
<p>如果$a_{11}$就是0，就是将某一行加上第一行，放入第一行。</p>
<p>要想办法将第一行的消元的数字变小，避免分数来当作消元元素来计算，造成自己出现很多失误。</p>
<ol start="2">
<li>对行列式，求某一行的余子式的相加</li>
</ol>
<p><a target="_blank" rel="noopener" href="https://www.bilibili.com/video/BV1aW411Q7x1?p=5">余子式累加实例24”51’讲解</a></p>
<p>这个解题一共3步骤推导：</p>
<p>1.余子式变成代数余子式，如果需要保持值不变，需要给式子配上符号；<br>2.将代数余子式提取出来，余子式和代数余子式符号不相同但是值相同；<br>3.将其他行都拿过来，将刚刚推出来的余子式的符号写入新的行列式；（还需要再看一次）<br>4.计算行列式的时候，选择行列式中0多的，然后计算。</p>
<p>思路是构造成新的一个行列式，然后算出最终值。原因是直接计算余子式，展开的项目太多了。</p>
<ol start="3">
<li>未知数提取<br>$$<br>\left|<br>\begin{matrix}<br>x&amp;a&amp;…&amp;a\</li>
</ol>
<p>\end{matrix}<br>\right|<br>$$</p>
<h2 id="行列式的计算（二）"><a href="#行列式的计算（二）" class="headerlink" title="行列式的计算（二）"></a>行列式的计算（二）</h2><p>之前的解题思路总结：</p>
<ol>
<li>将行列式转换成上三角；</li>
<li>将某行或列尽可能化成0，然后按行展开；</li>
</ol>
<p>其实这个就是<a target="_blank" rel="noopener" href="https://www.bilibili.com/video/BV1r5411J7YR?from=search&seid=14832837741932209290">高斯消元法</a> Gaussian Elimination。</p>
<h3 id="例6：加边法解方程"><a href="#例6：加边法解方程" class="headerlink" title="例6：加边法解方程"></a>例6：加边法解方程</h3><p>$$<br>\left|<br>\begin{matrix}<br>  1+a_{1}&amp;1&amp;1&amp;…&amp;1\<br>  1&amp;1+a_{2}&amp;1&amp;…&amp;1\<br>  …&amp;…&amp;…&amp;…&amp;…\<br>  1&amp;1&amp;1&amp;…&amp;1+a_{n}<br>\end{matrix}<br>\right|<br>$$</p>
<p>步骤：</p>
<p>1.加行加列</p>
<p>又叫做<strong>加边法</strong></p>
<p>准则：加边之后不能改变原行列式的值。</p>
<p>增加一行全部都写1，最前面增加一列，全部都写0。</p>
<p>实际做题很少使用的。</p>
<p>三叉戟行列式都是对角线上的数字，将首列的数字消元。</p>
<p>有字母，放到分母，一定要注意字母需要对非零的约束。</p>
<p><a target="_blank" rel="noopener" href="https://www.bilibili.com/video/BV1aW411Q7x1?p=6">书签1(15’22”)</a></p>
<p>$$<br>\left|<br>\begin{matrix}<br>  1&amp;1&amp;1&amp;1&amp;…&amp;1\<br>  0&amp;1+a_{1}&amp;1&amp;1&amp;…&amp;1\<br>  0&amp;1&amp;1+a_{2}&amp;1&amp;…&amp;1\<br>  …&amp;…&amp;…&amp;…&amp;…&amp;…\<br>  0&amp;1&amp;1&amp;1&amp;…&amp;1+a_{n}<br>\end{matrix}<br>\right|<br>$$</p>
<p>这里不变值原因来自于余子式相等。</p>
<p>2.将第一行$\times$-1加到剩余行</p>
<p>消元之后获得一个三叉戟行列式</p>
<p>$$<br>\left|<br>\begin{matrix}<br>  1&amp;1&amp;1&amp;1&amp;…&amp;1\<br>  -1&amp;a_{1}&amp;&amp;&amp;&amp;\<br>  -1&amp;&amp;1+a_{2}&amp;&amp;&amp;\<br>  …&amp;…&amp;…&amp;…&amp;…&amp;…\<br>  -1&amp;&amp;&amp;&amp;…&amp;a_{n}<br>\end{matrix}<br>\right|<br>$$</p>
<h3 id="例7：范德蒙德行列式"><a href="#例7：范德蒙德行列式" class="headerlink" title="例7：范德蒙德行列式"></a>例7：范德蒙德行列式</h3><p>$$<br>\left|<br>\begin{matrix}<br>  1&amp;1&amp;1&amp;1&amp;…&amp;1\<br>  x_1&amp;x_2&amp;1x_3&amp;x_4&amp;…&amp;x_n\<br>  …&amp;…&amp;…&amp;…&amp;…&amp;…\<br>  x_1^{n-2}&amp;x_2^{n-2}&amp;x_3^{n-2}&amp;x_4^{n-2}&amp; …&amp;x_n^{n-2}\<br>  x_1^{n-1}&amp;x_2^{n-1}&amp;x_3^{n-1}&amp;x_4^{n-1}&amp; …&amp;x_n^{n-1}<br>\end{matrix}<br>\right| =<br>\prod_{ 1 \leq j &lt; i \leq n }(x_i-x_j)<br>$$</p>
<p>其实第一行是0次幂运算。</p>
<p>$\prod$ 符号其实是连乘符号，和 $\sum$ 连加符号类似的模式，只是符号不相同。</p>
<p>公式里面两处很容易错：</p>
<p>j &lt; i，其他的值域限定都是 $\leq$，<em>其实也好理解 i = j的时候，会直接造成相减为0，这样行列式的值就直接=0</em>。</p>
<p>相减的时候是 $x_i-x_j$ ，这一点宋老师在课堂里面都写错过一次。</p>
<p>如果n=5的情况，写出结果来。</p>
<p>固定 j = 1</p>
<p>$(x_2-x1)<em>(x_3-x_1)</em>(x_4-x_1)*(x_5-x_1)$</p>
<p>固定 j = 2</p>
<p>$(x_3-x_2)<em>(x_4-x_2)</em>(x_5-x_2)$</p>
<p>…</p>
<p><a target="_blank" rel="noopener" href="https://www.bilibili.com/video/BV1aW411Q7x1?p=6">书签2(25’27”)</a></p>
<p>证明过程需要使用到的技巧：</p>
<ol>
<li>某一行乘上一个数，加到某一行去；定理7，这种是经常使用的；</li>
<li>数学归纳法—先证明2阶的，然后推算n阶和n-1阶，就能全部证明；</li>
<li>当某一列都乘以了某个数字，就可以将数字提取到行列式外；</li>
<li>使用减边法将行列式维度降低；</li>
</ol>
<p>在出题的时候，不会直白的给你说是范德蒙德行列式，通过两步隐藏起来。</p>
<ol>
<li>将指数运算藏起来；</li>
<li>将行列式转置；</li>
</ol>
<h3 id="例8：反对称行列式、对称行列式"><a href="#例8：反对称行列式、对称行列式" class="headerlink" title="例8：反对称行列式、对称行列式"></a>例8：反对称行列式、对称行列式</h3><p>定义：</p>
<p>反对称行列式：</p>
<p>奇数阶的行列式的值是为0的。</p>
<p>$$<br>\left|<br>\begin{matrix}<br>  0&amp;1&amp;2&amp;3\<br>  -1&amp;0&amp;-5&amp;6\<br>  -2&amp;5&amp;0&amp;-8\<br>  -3&amp;-6&amp;8&amp;0<br>\end{matrix}<br>\right|<br>$$</p>
<ol>
<li>主对角线全为零；</li>
<li>对称位置符号相反；$a_{ij}=-a_{ji}$</li>
</ol>
<p>奇数阶的行列式的值是为0的。</p>
<p>证明过程：</p>
<ol>
<li>先使用3阶的行列式；</li>
<li>将全部行列都提取一个-1；</li>
<li>将会发现行列式变成了转置行列式；</li>
<li>而且转置行列式的值和原始值保持不变$D^t=D$，所以能推算出0；</li>
</ol>
<p>对称行列式：</p>
<p>$$<br>\left|<br>\begin{matrix}<br>  1&amp;1&amp;-1\<br>  1&amp;2&amp;0\<br>  -1&amp;0&amp;3<br>\end{matrix}<br>\right|<br>$$</p>
<ol>
<li>主对角线任意数值；</li>
<li>对称位置完全相同；$a_{ij}=a_{ji}$</li>
</ol>
<p><a target="_blank" rel="noopener" href="https://www.bilibili.com/video/BV1aW411Q7x1?p=6">书签3(44’19”)</a></p>
<p>后续的对称矩阵、反对称矩阵和行列式的定义是一样的。</p>
<h2 id="克莱姆法则-Cramer’s-rule"><a href="#克莱姆法则-Cramer’s-rule" class="headerlink" title="克莱姆法则 Cramer’s rule"></a>克莱姆法则 Cramer’s rule</h2><p>用来解方程组的。</p>
<p>$$\begin{cases}<br>x_1+x_2+x_3=1\<br>x_1-x_2+5x_3=6\<br>-x_1+x_2+6x_3=9<br>\end{cases}$$</p>
<p>3个方程，3个未知数。</p>
<p>应用条件：</p>
<ol>
<li><p>n方程式个数和n未知数相同。</p>
</li>
<li><p>系数行列式，其实就是提取了系数形成的行列式；行列式的值不能为0。$D\neq0$。看到后面才会知道，D将会作为除数，一旦=0，就完蛋了。</p>
</li>
</ol>
<p>定义4个行列式的值：</p>
<p>D为原始的，$D_{1}$是将第一列全部数字都替换成方程组的值这一列，以此类推。</p>
<p>$$D=\left|<br>\begin{matrix}<br>  1&amp;1&amp;1\<br>  1&amp;-1&amp;5\<br>  -1&amp;1&amp;6<br>\end{matrix}\right|<br>D_{1}=\left|<br>\begin{matrix}<br>  (1)&amp;1&amp;1\<br>  (6)&amp;-1&amp;5\<br>  (9)&amp;1&amp;6<br>\end{matrix}\right|<br>D_{2}=\left|<br>\begin{matrix}<br>  1&amp;(1)&amp;1\<br>  1&amp;(6)&amp;5\<br>  -1&amp;(9)&amp;6<br>\end{matrix}\right|<br>D_{3}=\left|<br>\begin{matrix}<br>  1&amp;1&amp;(1)\<br>  1&amp;-1&amp;(6)\<br>  -1&amp;1&amp;(9)<br>\end{matrix}\right|<br>$$</p>
<p>最终公式为：</p>
<p>$$ x_{1}=\frac{D_1}{D},x_{2}=\frac{D_2}{D},x_{3}=\frac{D_3}{D} $$</p>
<p>克莱姆法则其实不适合人类计算，但是非常适合计算机来运算解题。</p>
<blockquote>
<p>注： 齐次方程组：当方程组的常数项都为0的情况，就是齐次方程组。（课堂里第一次提到这个概念）</p>
</blockquote>
<blockquote>
<p>定理：</p>
</blockquote>
<blockquote>
<p>齐次方程组：</p>
<p>有非零解的<em>充要条件</em>是$D=0$</p>
<p>$D\neq0$，只有零解</p>
</blockquote>
<h1 id="2-矩阵-Matrix"><a href="#2-矩阵-Matrix" class="headerlink" title="2. 矩阵 Matrix"></a>2. 矩阵 Matrix</h1><h2 id="矩阵概念"><a href="#矩阵概念" class="headerlink" title="矩阵概念"></a>矩阵概念</h2><p>有了行列式，为什么要出一个矩阵的概念。</p>
<p>$行 \times 列$ 矩阵，是数表。</p>
<p>$A_{2 \times 3}$。</p>
<p>矩阵和行列式的区别：</p>
<table>
<thead>
<tr>
<th align="left"></th>
<th align="left">行列式</th>
<th align="left">矩阵</th>
</tr>
</thead>
<tbody><tr>
<td align="left">本质</td>
<td align="left">一个数字</td>
<td align="left">数表</td>
</tr>
<tr>
<td align="left">符号</td>
<td align="left">|</td>
<td align="left">(（注{大括号在行列式里面不会使用。）</td>
</tr>
<tr>
<td align="left">形状</td>
<td align="left">行数=列数</td>
<td align="left">行数可以不等于列数</td>
</tr>
<tr>
<td align="left">提公因子</td>
<td align="left">一行提一次</td>
<td align="left">全部的元素的公因子提一次</td>
</tr>
</tbody></table>
<p>矩阵里面有实数矩阵、复数矩阵。</p>
<h2 id="零矩阵"><a href="#零矩阵" class="headerlink" title="零矩阵"></a>零矩阵</h2><p>元素都为0的矩阵。</p>
<h2 id="负矩阵"><a href="#负矩阵" class="headerlink" title="负矩阵"></a>负矩阵</h2><p>A -A</p>
<p>矩阵行列相等就是方阵</p>
<p>$A_{n \times n} = A_{n}$</p>
<h2 id="单位矩阵"><a href="#单位矩阵" class="headerlink" title="单位矩阵"></a>单位矩阵</h2><p>符号用E,I，一定是方阵。</p>
<p>$$E,I=\left(<br>  \begin{matrix}<br>    1&amp;&amp;&amp;\<br>    &amp;1&amp;&amp;\<br>    &amp;&amp;1&amp;\<br>    &amp;&amp;&amp;1<br>  \end{matrix}<br>\right)$$</p>
<p>除了主对角线都为1，其他都为0。</p>
<p>矩阵相等前提是同形矩阵。</p>
<p>零矩阵可能不相等，因为可能不同形状。</p>
<p>方阵才有主对角线，此对角线。</p>
<h2 id="矩阵运算（一）"><a href="#矩阵运算（一）" class="headerlink" title="矩阵运算（一）"></a>矩阵运算（一）</h2><p>线性代数有176个知识点。老师打印了一张A4纸，两面写满。</p>
<h3 id="加法"><a href="#加法" class="headerlink" title="加法"></a>加法</h3><p>同形矩阵才能加，对应元素能加减。</p>
<h3 id="减法"><a href="#减法" class="headerlink" title="减法"></a>减法</h3><p>同形矩阵才能减，对应元素能加减。</p>
<p>运算交换律，结合律都满足。</p>
<h3 id="数乘"><a href="#数乘" class="headerlink" title="数乘"></a>数乘</h3><p>其实就是将一个标量与矩阵相乘。</p>
<h3 id="提公因子"><a href="#提公因子" class="headerlink" title="提公因子"></a>提公因子</h3><p>矩阵的所有元素均有公因子，才能对外提一次公因子。</p>
<p>行列式提公因子是一行提一次。</p>
<p>乘法的结合律和交换律是合适用的。</p>
<h3 id="矩阵的乘法（非常重要）"><a href="#矩阵的乘法（非常重要）" class="headerlink" title="矩阵的乘法（非常重要）"></a>矩阵的乘法（非常重要）</h3><p>看起来很容易，其实做题很多坑。</p>
<p><a target="_blank" rel="noopener" href="https://www.bilibili.com/video/BV1aW411Q7x1?p=9&spm_id_from=pageDriver">书签4-14’19”</a></p>
<h4 id="矩阵乘法速记"><a href="#矩阵乘法速记" class="headerlink" title="矩阵乘法速记"></a>矩阵乘法速记</h4><p>$$\left(<br>  \begin{matrix}<br>    2&amp;1&amp;0\<br>    1&amp;0&amp;1<br>  \end{matrix}<br>\right)\left(<br>  \begin{matrix}<br>    1&amp;0&amp;1\<br>    0&amp;1&amp;1\<br>    0&amp;1&amp;1<br>  \end{matrix}<br>\right)=\left(<br>  \begin{matrix}<br>    2&amp;1&amp;3\<br>    1&amp;1&amp;2<br>  \end{matrix}<br>\right)<br>$$</p>
<p>$$A_{2\times 3} \times B_{2} $$</p>
<p>矩阵相乘前提条件：</p>
<p>第一个矩阵的列数=第二个矩阵的行数。</p>
<p>相乘结果：</p>
<p>行数第一个矩阵相等。</p>
<p>列数和第二个矩阵相等。</p>
<p>宋老师七字口诀：</p>
<p>$$A_{3 \times 4} B_{4 \times 5} $$</p>
<p>中间相等，取两头。</p>
<p>其实就是罗列矩阵的下标数字：</p>
<p>3,4,4,5</p>
<p>中间数字： 4,4相等，就能乘；</p>
<p>取两头： 3,5 这就是结果的矩阵的形状。</p>
<p>$$\left(<br>  \begin{matrix}<br>    -1&amp;1&amp;5\<br>    4&amp;3&amp;-2<br>  \end{matrix}<br>\right) \left(<br>  \begin{matrix}<br>    1&amp;-1\<br>    0&amp;2\<br>    -3&amp;6<br>  \end{matrix}<br>\right)=?<br>$$</p>
<p>得出公式：</p>
<p>$$A_{2 \times 3} B_{3 \times 2} = C_{2 \times 2}$$</p>
<h4 id="乘法不满足的三规律"><a href="#乘法不满足的三规律" class="headerlink" title="乘法不满足的三规律"></a>乘法不满足的三规律</h4><ol>
<li>乘法是不满足交换律</li>
</ol>
<p>$$AB \neq BA$$</p>
<p>AB能相乘的情况下，BA都可能不能乘。</p>
<p>但是也有可能存在AB可交换。</p>
<p>AB读的时候：</p>
<p>A左乘B</p>
<p>B右乘A</p>
<ol start="2">
<li><p>由AB=0,无法推理出A=0或者B=0。</p>
</li>
<li><p>推理相等</p>
</li>
</ol>
<p>$$AB=AC, A \neq 0 $$无法推理出 $$B=C$$</p>
<h4 id="与零矩阵相乘"><a href="#与零矩阵相乘" class="headerlink" title="与零矩阵相乘"></a>与零矩阵相乘</h4><p>都是相乘之后就等0。</p>
<h4 id="与E（单位矩阵）相乘"><a href="#与E（单位矩阵）相乘" class="headerlink" title="与E（单位矩阵）相乘"></a>与E（单位矩阵）相乘</h4><p>AE=A EB=B</p>
<h4 id="结合律分配律"><a href="#结合律分配律" class="headerlink" title="结合律分配律"></a>结合律分配律</h4><p>在结合分配率使用的时候，位置一定不变。</p>
<p>结合律：(AB)C=A(BC)<br>分配律：(A+B)C=AC+BC,C(A+B)=CA+CB<br>数乘：k(AB)=(kA)B=A(kB)</p>
<h4 id="例6：可交换"><a href="#例6：可交换" class="headerlink" title="例6：可交换"></a>例6：可交换</h4><ol>
<li>其实按矩阵乘法展开；</li>
<li>列出方程式；</li>
<li>最后获得答案；</li>
</ol>
<p>其实有规律，两个矩阵是同阶的方阵，才能做这个计算。</p>
<h4 id="例7："><a href="#例7：" class="headerlink" title="例7："></a>例7：</h4><p>从方程组转换成为矩阵。</p>
<p>使用矩阵相乘获取最终的答案。</p>
<p>$$\begin{cases}<br>x_1=y_1-y_2\<br>x_2=y_1+y2<br>\end{cases}<br>\begin{cases}<br>y_1=z_1+z_2+z_3\<br>y2=z_1+2z_2+z3<br>\end{cases}<br>\begin{cases}<br>z_1=u_1+u_2\<br>z_2=u_1+0u_2\<br>z_2=-u_1+u_2<br>\end{cases}<br>$$</p>
<p>如何将</p>
<p>$$\left(<br>  \begin{matrix}<br>    x_1\<br>    x_2<br>  \end{matrix}<br>\right)<br>$$</p>
<p>数值计算出来？</p>
<h2 id="矩阵运算（二）"><a href="#矩阵运算（二）" class="headerlink" title="矩阵运算（二）"></a>矩阵运算（二）</h2><h3 id="矩阵幂运算"><a href="#矩阵幂运算" class="headerlink" title="矩阵幂运算"></a>矩阵幂运算</h3><p>$A^k = \underbrace{AA…A}_{k个}$</p>
<p>定义：</p>
<p>$A^0=E$</p>
<p>性质1：</p>
<p>$A^{K_1}A^{K_2}=A^(k_1+k2)$</p>
<p>性质2：</p>
<p>$(A^{k_1})^{k_2}=A^{k_1k_2}$</p>
<p>性质3：</p>
<p>一般来说：</p>
<p>$(AB)^k \neq A^k B^k$</p>
<p>$(A+B)^2 \neq A^2 + 2AB+B^2$</p>
<p>还是来自于AB和BA不相等造成的。</p>
<p>$(A-B)^2 \neq A^2-2AB+B^2$</p>
<p>如果B=E单位向量，那就是成立的。</p>
<p>例八：</p>
<p>思维锻炼方法，告辞米的时候，需要跳出来做。</p>
<p>去将一个中间的数字计算出一个常数，然后提取出来。</p>
<h3 id="转置"><a href="#转置" class="headerlink" title="转置"></a>转置</h3><p>$A^T$</p>
<p>和行列式的转置是完全一样的。</p>
<p>$A_{m \times n}^T=A_{n \times m}$</p>
<p>性质：</p>
<p>$(A^T)^T=A$</p>
<p>$(A+B)^T=A^T+B^T$</p>
<p>$(kA)^T=kA^T$</p>
<p>$(AB)^T=B^T A^T$</p>
<h2 id="特殊矩阵"><a href="#特殊矩阵" class="headerlink" title="特殊矩阵"></a>特殊矩阵</h2><h3 id="数量矩阵"><a href="#数量矩阵" class="headerlink" title="数量矩阵"></a>数量矩阵</h3><p>只有主对角线有值，且相等。</p>
<h3 id="对角形矩阵"><a href="#对角形矩阵" class="headerlink" title="对角形矩阵"></a>对角形矩阵</h3><p>只有主对角线有值，且有一串数字。</p>
<p>数学符号：</p>
<p>$\diagdown$</p>
<p>$diag(a_1,a_2,…,a_n)$</p>
<p>对角形矩阵左乘与右乘相同的方阵，刚好是转置的。</p>
<h3 id="三角形矩阵"><a href="#三角形矩阵" class="headerlink" title="三角形矩阵"></a>三角形矩阵</h3><p>主对角线上部非零，下部都是0，就是上三角矩阵。</p>
<p>主对角线下部非零，下部都是0，就是下三角矩阵。</p>
<h3 id="对称矩阵"><a href="#对称矩阵" class="headerlink" title="对称矩阵"></a>对称矩阵</h3><p>对称矩阵有个性质</p>
<p>$a_{ij}=a_{ji}$</p>
<p>本质上是：</p>
<p>$A^T=A$</p>
<p>定理1：</p>
<p>$A,B对称 \rightleftarrows AB可交换$</p>
<p>例2</p>
<p>反对称矩阵</p>
<p>$a_{ij}=-a_{ji}，a_{ii}=0$</p>
<p>$A^T=-A$</p>
<h2 id="逆矩阵（一）"><a href="#逆矩阵（一）" class="headerlink" title="逆矩阵（一）"></a>逆矩阵（一）</h2><p>逆矩阵就是将两个逆矩阵相乘之后能得到单位向量。</p>
<p>一定不要把矩阵放到分母的位置上。</p>
<p>方阵的行列式。</p>
<p>矩阵式有很多属性，但是行列式是一个数字。</p>
<p>$$矩阵\begin{cases}<br>  特值\<br>  特量\<br>  行列式\<br>  …<br>\end{cases}<br>$$</p>
<p>获取矩阵的行列式，其实就是将它的属性提取出来。</p>
<h3 id="方阵的行列式"><a href="#方阵的行列式" class="headerlink" title="方阵的行列式"></a>方阵的行列式</h3><p>性质1：</p>
<p>$$\left|<br>A^T<br>\right|=\left|<br>A\right|$$</p>
<p>原理就是行列式转置，值不变。</p>
<ul>
<li>性质2：</li>
</ul>
<p>$$\left|<br>kA<br>\right|=k^n\left|<br>A\right|$$</p>
<p>行列式和矩阵提取的方式不一样造成。</p>
<p>性质3：</p>
<p>$$\left|<br>AB<br>\right|=\left|<br>A\right|\left|<br>B\right|$$</p>
<h3 id="伴随矩阵-A"><a href="#伴随矩阵-A" class="headerlink" title="伴随矩阵 $A^*$"></a>伴随矩阵 $A^*$</h3><p>只有方阵才有伴随矩阵。</p>
<ol>
<li>求出全部元素的代数余子式；</li>
<li>按照行求的代数余子式，按照列放，构成一个矩阵就是伴随矩阵；</li>
</ol>
<p>数学符号：</p>
<p>$A^*$ </p>
<p>口诀：</p>
<p><em>按行求，按列放</em></p>
<p>定理1：</p>
<p>对于任意的一个方阵都成立。</p>
<p>$AA^*=A^*A=\left|A\right|E$</p>
<p>证明过程：</p>
<p>代数余子式乘以自己本身就是行列式的值，否则就是0；定理就是异乘变零定理，章节1.3里面写过；</p>
<p>推论2.4.1</p>
<p>前提条件:</p>
<p>$\left|A\right| \neq 0$</p>
<p>$\left|A^*\right|=\left|A\right|^{n-1}$</p>
<p>后续再证明当不等0的情况也合适。</p>
<h2 id="逆矩阵（二）"><a href="#逆矩阵（二）" class="headerlink" title="逆矩阵（二）"></a>逆矩阵（二）</h2><h3 id="伴随矩阵法"><a href="#伴随矩阵法" class="headerlink" title="伴随矩阵法"></a>伴随矩阵法</h3><p>逆矩阵定义： A是n阶方阵，存在n阶方阵B， </p>
<p>$AB=BA=E$</p>
<p>$A^-1=B$</p>
<p>但是方阵一定不要放到分母中！</p>
<ol>
<li><p>未必所有方阵都可逆；</p>
</li>
<li><p>若可逆，逆矩阵唯一；</p>
</li>
</ol>
<p>证明是通过结合律。</p>
<p>？ 如何判断是否可逆；</p>
<p>？ 如何求出逆矩阵；</p>
<p><a target="_blank" rel="noopener" href="https://www.bilibili.com/video/BV1aW411Q7x1?p=13&spm_id_from=pageDriver">书签-12’10”</a></p>
<p>定义： 如果：$\left|A\right| \neq 0$ 就说明：非奇异/非退化/满秩，说明可逆。否则相反。</p>
<p>定理： A矩阵可逆的充要条件是 $\left|A\right| \neq 0$，且 $A^{-1}=\frac{1}{\left|A\right|}A^{*}$</p>
<p>证明过程：</p>
<ol>
<li>充分性</li>
</ol>
<p>$\left|A\right| \neq 0$</p>
<p>（后面需要使用这个来做分母。）</p>
<ol start="2">
<li>只要A矩阵是一个方阵就有这个式子的成立（永远成立）：</li>
</ol>
<p>$AA^*=A^*A=\left|A\right|E$</p>
<p>（这个概念在上一节说伴随矩阵的定义的时候说的。）</p>
<ol start="3">
<li><p>将式子全部除以 $\frac{1}{\left|A\right|}$</p>
</li>
<li><p>从逆矩阵的定义出发</p>
</li>
</ol>
<p>$AB=BA=E$</p>
<p>B就是A的逆矩阵。</p>
<p>最终推理出这个式子。</p>
<p>推论： An方 Bn方 AB=E 演算一次就好了，而BA的可逆，是一定可以的。（常用）</p>
<p>前提：</p>
<p>$AB=E$</p>
<p>所以</p>
<p>$\left|A\right|\left|B\right|=1$</p>
<p>两数相乘不等于0，说明两个数字都不为零。</p>
<p>不为零的方正一定可逆。</p>
<p>总结：</p>
<p>这种求矩阵的方法为<em>伴随矩阵法</em>。按照计算量来说，估计又是给计算机来用的。</p>
<h3 id="初等变换法（考试的时候常用法）"><a href="#初等变换法（考试的时候常用法）" class="headerlink" title="初等变换法（考试的时候常用法）"></a>初等变换法（考试的时候常用法）</h3><p>矩阵方程：</p>
<p>$AX=A+2X$</p>
<p>$$A=\left(\begin{matrix}<br>  4&amp;2&amp;3\<br>  1&amp;1&amp;0\<br>  -1&amp;2&amp;3<br>\end{matrix}<br>  \right)<br>$$</p>
<p>常见错误集合：</p>
<ol>
<li>矩阵相乘需要检查矩阵是否同形；</li>
<li>矩阵永远不要放到分母上；</li>
<li>矩阵的乘法不满足交换律，所以自己想，或者和人沟通的时候，一定要定义为左乘，或者右乘；</li>
<li>矩阵不是一定可逆的，所以在做转换的时候不能直接就这样认为；想要用这个，就需要先证明；</li>
<li>注意提数出去的时候，方向问题，这一点和左乘，右乘类似；</li>
</ol>
<p><a target="_blank" rel="noopener" href="https://www.bilibili.com/video/BV1aW411Q7x1?p=13&spm_id_from=pageDriver">书签-46’40”</a></p>
<p>这些东西都容易糊涂的。</p>
<p>待定法（假借法）。这种基本上太耗费时间，人在考试的时候，基本上解不完这个题目。</p>
<p>考试的时候一定是使用初等变换法来解题。</p>
<p>性质6： A可逆，$A^{-1}$可逆，$(A^{-1})^{-1}=A$</p>
<p>$(A^{-1})^{-1}A (A^T)^T=A$</p>
<p>推论： AB=E,$A^{-1}=B$</p>
<p>$(AB)^{-1}=B^{-1}A^{-1} (AB)^{T}=B^{T}A^{T}$</p>
<p>性质：</p>
<p>A可逆，$A^T$可逆 $(A^T)^{-1}=(A^{-1})^T$</p>
<p>下面这个式子，证明的时候，需要使用逆矩阵去括号之后交换。</p>
<p>$A^T(A^{-1})^{T}=(A^{-1}A)^T=E^T=E$</p>
<p>逆矩阵朝外提的时候，是需要放到分母上。具体证明，还是需要带入定义公式。</p>
<p>$k\neq0 (kA)^{-1}=\frac{1}{k}A^{-1}$</p>
<p>性质7： A可逆 $\left|A^{-1}\right|=\left|A\right|^{-1}$</p>
<p>再次强调，非零的行列式能作为分母，任何矩阵都不能作为分母。</p>
<p>性质8： A可逆，$A^*$也可逆， $(A^*)^{-1}=\frac{1}{\left|A\right|}A$</p>
<p>证明过程：</p>
<p>伴随矩阵的恒等式</p>
<p>$AA^*=\left|A\right|E$ 两边都除以 $\left|A\right|$，再根据逆矩阵相乘等于单位阵，可以推论出来式子。</p>
<p>伴随矩阵总结 $A^*$</p>
<ol>
<li>按行求，按列放</li>
<li>$AA^*=\left|A\right|E$</li>
<li>$\left|A^*\right|=\left|A\right|^{n-1}$</li>
<li>$\left|A^{-1}\right|=\left|A\right|^{-1} A^*=\left|A^{-1}\right|A^{-1}$</li>
</ol>
<p>思考题：</p>
<p>$(A^*)^*=\left|A^<em>\right|(A^</em>)^{-1}=\left|A\right|^{n-1}\frac{1}{\left|A\right|}A=\left|A\right|^{n-2}A$</p>
<p>前面部分都是需要使用公式的带入，最后一步，</p>
<p>$((A^*)^*)^*=\left|A\right|^{n^2-3n+3}A^{-1}$</p>
<h2 id="分块矩阵"><a href="#分块矩阵" class="headerlink" title="分块矩阵"></a>分块矩阵</h2><p>$$\left(\begin{matrix}<br>  1&amp;1&amp;3&amp;4&amp;0\<br>  2&amp;0&amp;1&amp;1&amp;0\<br>  1&amp;1&amp;1&amp;1&amp;3\<br>  4&amp;1&amp;1&amp;1&amp;0<br>\end{matrix}<br>\right)$$</p>
<p>标准形，从左上角开始的一串1（不断）。标准形不一定是方的。</p>
<p>全部都是0的矩阵，也是标准形。</p>
<p>分块矩阵做加法</p>
<p>加法的时候，必须形状一样的。对应位置的数字相加。</p>
<p>数乘</p>
<p>直接将标量数字乘上全部元素。</p>
<p>乘法</p>
<p>类似矩阵相乘。</p>
<p>有前提条件，矩阵中间相同。</p>
<p>分块矩阵的转置：</p>
<ol>
<li>先将子块当成普通元素先转置；</li>
<li>再将每个子块做转置；</li>
</ol>
<p>例6 分块矩阵求逆的过程记录一下。</p>
<h2 id="初等变换（一）"><a href="#初等变换（一）" class="headerlink" title="初等变换（一）"></a>初等变换（一）</h2><p>初等变换，行、列变换</p>
<p>行变换：</p>
<p>交换两行</p>
<p>用k$k\neq0$乘以某一行</p>
<p>某一行乘$ell$倍加到另一行上去。注意$ell$可以为零</p>
<p>列变换，其实和行变换相似。</p>
<p>符号是使用箭头链接，不要用等号。</p>
<p>本质：对矩阵的变化。</p>
<p>这些对应行列式里面也有类似的定义，但是行列式和矩阵不一样。注意矩阵和行列式的交换没有任何关系。</p>
<p>初等变换矩阵不要求式方阵。</p>
<p>只有在方阵的时候，才有可能二者有联系。</p>
<p>定理1：任意给一个矩阵，都可以通过初等变换化为标准形。（行、列变换都可以）</p>
<p>考点：给定一个矩阵，化为标准形。标准形，在上节课讲过。</p>
<h2 id="初等变换（二）"><a href="#初等变换（二）" class="headerlink" title="初等变换（二）"></a>初等变换（二）</h2><h2 id="初等变换（三）"><a href="#初等变换（三）" class="headerlink" title="初等变换（三）"></a>初等变换（三）</h2><h2 id="矩阵的秩（一）"><a href="#矩阵的秩（一）" class="headerlink" title="矩阵的秩（一）"></a>矩阵的秩（一）</h2><h2 id="矩阵的秩（二）"><a href="#矩阵的秩（二）" class="headerlink" title="矩阵的秩（二）"></a>矩阵的秩（二）</h2><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><ul>
<li>[1] <a target="_blank" rel="noopener" href="https://muzhan.blog.csdn.net/article/details/81385790?utm_medium=distribute.pc_relevant.none-task-blog-searchFromBaidu-3.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-searchFromBaidu-3.control">markdown公式1</a></li>
<li>[2] <a target="_blank" rel="noopener" href="http://www2.edu-edu.com.cn/lesson_crs78/self/j_0022/soft/ch0604.html">求解线性方程组实例</a></li>
<li>[3] <a target="_blank" rel="noopener" href="https://www.bilibili.com/video/BV1aW411Q7x1?from=search&seid=11900062682580761753">宋洁老师-行列式</a></li>
<li>[4] <a target="_blank" rel="noopener" href="https://space.bilibili.com/88461692">3Blue1Brown</a></li>
<li>[5] <a target="_blank" rel="noopener" href="https://latex.91maths.com/">在线LaTex工具</a></li>
<li>[6] <a target="_blank" rel="noopener" href="http://www.ptep-online.com/ctan/lshort_chinese.pdf">LaTex语法</a></li>
<li>[7] <a target="_blank" rel="noopener" href="https://baike.baidu.com/item/%E9%AB%98%E6%96%AF%E6%B6%88%E5%85%83%E6%B3%95/619561?fr=aladdin">高斯消元法</a></li>
</ul>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://example.com/2021/01/22/2021/2021-01-22-%E7%BA%BF%E6%80%A7%E4%BB%A3%E6%95%B0/" data-id="ckrn3an7r002k20xw8emgaj6y" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Math/" rel="tag">Math</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-2021/2021-01-14-UnrealEngine4" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2021/01/14/2021/2021-01-14-UnrealEngine4/" class="article-date">
  <time datetime="2021-01-13T16:00:00.000Z" itemprop="datePublished">2021-01-14</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2021/01/14/2021/2021-01-14-UnrealEngine4/">虚幻引擎程序设计浅析</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <p>开一篇文章记录学习Unreal Engine相关知识。参考《虚幻引擎程序设计浅析》ISBN 978-7-121-31349-3，电子工业出版社。带着问题来学习，才能学的快速。看书先需要阅读的就是作者划分的章节目录，反复多看几遍，能从总体上看出知识的结构。</p>
<h1 id="第一部分-虚幻引擎C-编程"><a href="#第一部分-虚幻引擎C-编程" class="headerlink" title="第一部分 虚幻引擎C++编程"></a>第一部分 虚幻引擎C++编程</h1><h2 id="第1章-五个类的熟悉"><a href="#第1章-五个类的熟悉" class="headerlink" title="第1章 五个类的熟悉"></a>第1章 五个类的熟悉</h2><p>最首先了解5个类，比较关键。</p>
<p>UObject Actor Pawn Controller Character</p>
<ol>
<li>UObject</li>
</ol>
<p>提供垃圾回收</p>
<p>这个功能和c++标准中的智能指针是冲突的。</p>
<p>反射</p>
<p>相当于实现了java、c#中的反射功能。在本书的第二部分解释了。</p>
<p>序列化</p>
<p>提供无损的加载，序列化方便保存到磁盘或者传递给远端服务器。</p>
<p>与虚幻引擎编辑器的交互</p>
<p>可以在Editor面板里面方便的使用。</p>
<p>运行时类型识别</p>
<p>这个功能也会和C++标准中的RTTI机制：dynamic_cast有冲突。一旦使用，要使用Cast&lt;&gt;函数做类型转换。虚幻号称会提供更加高效的类型识别。</p>
<p>网络复制</p>
<p>在c/s架构中，其被宏标记的变量能够自动完成网络复制。从服务器端复制对应值到客户端。</p>
<ol start="2">
<li>Actor</li>
</ol>
<p>它能被挂载组件Component。</p>
<p>UE中的Component和unity的是很大的不同。在虚幻里面，Component含义被极大削弱。</p>
<ol start="3">
<li>灵魂与肉体：Pawn、Character和Controller</li>
</ol>
<p>Pawn类是提供被操控的特性。它能被Controller操控，Controller可以是用户输入或者AI。Pawn离开操控者无法自主行动的肉体。</p>
<p>Character继承于Pawn。提供了特殊组件，Character Movement组件。提供基础的、基于胶囊体的角色移动，跳跃之类的。</p>
<p>Controller</p>
<p>操控肉体的类，肉体拥有前行、转向、跳跃、开火等函数。类似MVC设计模式。Controller就是管理器，Pawn就是Model，而Pawn挂载的动态网格组件就是View。这个例子也不算太合适能初略建立概念。</p>
<h2 id="第2章-需求到实现"><a href="#第2章-需求到实现" class="headerlink" title="第2章 需求到实现"></a>第2章 需求到实现</h2><ol>
<li>分析需求</li>
</ol>
<p>使用UML工程建模工具绘制需求分析图。</p>
<p>或者通过沟通分析出来简短的短语。</p>
<ol start="2">
<li>转化需求为设计</li>
</ol>
<p>首先从短语中抽象出里面重要的名词，这样就是我们的类。</p>
<p>然后分析出类之间的持有、通信关系。</p>
<h2 id="第3章-创建自己的C-类"><a href="#第3章-创建自己的C-类" class="headerlink" title="第3章 创建自己的C++类"></a>第3章 创建自己的C++类</h2><ol>
<li>使用Unreal Editor创建c++类</li>
</ol>
<p>“内容浏览器” -&gt; “右键” -&gt; “新建C++类”</p>
<p>有一个创建的流程，可以在过程中选择基类。输入名称选择路径。</p>
<ol start="2">
<li>手动创建C++类</li>
</ol>
<p>文件目录结构为</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">--public/</span><br><span class="line">--private/</span><br><span class="line">--.build.cs</span><br></pre></td></tr></table></figure>

<p>头文件放到public文件夹，cpp放入private文件夹。</p>
<p>如果继承了UE的类，需要增加一些宏，否则编译不过。</p>
<p>cpp文件中包含pch文件。</p>
<ol start="3">
<li>虚幻引擎类命名规则</li>
</ol>
<blockquote>
<p>F 纯C++类<br>U 继承自UObject，但不继承Actor<br>A 继承自Actor<br>S Slate控件相关类<br>H HitResult相关类</p>
</blockquote>
<p>Unreal Header Tool 会在编译之前检查这些类名的约束。</p>
<h2 id="第4章-对象"><a href="#第4章-对象" class="headerlink" title="第4章 对象"></a>第4章 对象</h2><ol>
<li>类对象的产生</li>
</ol>
<p>如果是纯C++类型，可以通过new产生。</p>
<p>如果你的类继承自UObject，需要通过NewObject函数来产生。</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">NewObject&lt;T&gt;();</span><br></pre></td></tr></table></figure>

<p>如果继承自AActor，需要通过SpawnActor函数产生对象。</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">GetWorld</span>()-&gt;SpawnActor&lt;AYourActorClass&gt;();</span><br></pre></td></tr></table></figure>

<ol start="2">
<li>类对象的获取</li>
</ol>
<p>通过对象的引用或者指针来获取。GetWorld能使用IActorIterator<AACtor>迭代World里面全部的Actor。</p>
<ol start="3">
<li>类对象的销毁</li>
</ol>
<p>纯C++类型，就是自己delete就可以了。</p>
<p>UObject的对象，本身有一套内存管理机制，当没有对象引用了，就会触发GC。</p>
<p>Actor的对象，通过Destory函数请求销毁，这个只是说从World里面摘除掉，内存回收还需要靠引擎来决定。</p>
<h2 id="第5章-从C-到蓝图"><a href="#第5章-从C-到蓝图" class="headerlink" title="第5章 从C++到蓝图"></a>第5章 从C++到蓝图</h2><p>让蓝图调用我的C++类。</p>
<ol>
<li>UPROPERTY宏</li>
</ol>
<p>将成员变量注册到蓝图中。</p>
<ol start="2">
<li>UFUNCTION宏</li>
</ol>
<p>注册函数到蓝图中。</p>
<h2 id="第6章-游戏性框架概述"><a href="#第6章-游戏性框架概述" class="headerlink" title="第6章 游戏性框架概述"></a>第6章 游戏性框架概述</h2><h3 id="1-行为树：概念与原理"><a href="#1-行为树：概念与原理" class="headerlink" title="1. 行为树：概念与原理"></a>1. 行为树：概念与原理</h3><ol>
<li>为什么选择行为树</li>
</ol>
<p>ue3框架是状态机制作的，还引入了Unreal Script脚本来扩展。在ue4直接被行为树系统替换。状态机只在动画蓝图中保留。</p>
<p>粗俗来说，行为树特点：“逐个尝试，不行就换”的思路。更加符合人的思维方式。</p>
<ol start="2">
<li>行为树原理</li>
</ol>
<p>三种节点：</p>
<blockquote>
<p>流程控制：包含Selector选择器和Sequence顺序执行器。<br>装饰器：对子树的返回值进行处理的节点。<br>执行节点：干活的节点，返回trun或者false，running。</p>
</blockquote>
<p>可以参考之前写过的行为树的文档，里面也有if语句，&amp;&amp;||的逻辑运算，挂起唤醒逻辑，循环逻辑等等。是一种使用可视化方式提供给别人来编写程序的一种方法。</p>
<h3 id="2-虚幻引擎网络框架构"><a href="#2-虚幻引擎网络框架构" class="headerlink" title="2. 虚幻引擎网络框架构"></a>2. 虚幻引擎网络框架构</h3><ol>
<li>同步</li>
</ol>
<p>多人在线的同步问题，是通过一台<em>权威服务器</em>来负责将数据收集起来，并且分发给客户端。让作弊变得困难。</p>
<blockquote>
<p>指令：对于游戏世界造成影响的请求。egg：人物前移3米，人物挥刀碰到了怪物<br>状态：游戏世界的各种数值状态。egg：当前人物生命值，当前怪物生命值。</p>
</blockquote>
<p>客户端只能向服务器发送“指令”，服务器根据指令处理之后，改变游戏世界的状态，并且将状态<em>同步</em>给每个客户端。</p>
<ol start="2">
<li>广义的客户端-服务器模型</li>
</ol>
<blockquote>
<p>客户端是对服务器的拙劣模仿 — 虚幻官方文档UDN中描述<br>“拙劣”二字，表示是服务器的世界是正确的，而客户端则是不断试图猜测服务器当前的状态，并且模仿。</p>
</blockquote>
<h2 id="第7章-引擎系统相关类"><a href="#第7章-引擎系统相关类" class="headerlink" title="第7章 引擎系统相关类"></a>第7章 引擎系统相关类</h2><p>本章主要介绍一些虚幻引擎4提供的一些类，防止程序重复造轮子。</p>
<h3 id="7-1-正则表达式"><a href="#7-1-正则表达式" class="headerlink" title="7.1 正则表达式"></a>7.1 正则表达式</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&quot;Regex.h&quot;</span></span></span><br><span class="line"><span class="function">FString <span class="title">TextStr</span><span class="params">(<span class="string">&quot;AAAABBBBB&quot;</span>)</span></span>;</span><br><span class="line"><span class="function">FRegexPattern <span class="title">TestPattern</span><span class="params">(TEXT(<span class="string">&quot;C.+H&quot;</span>))</span></span>;</span><br><span class="line">FRegexMatcher xxx;</span><br></pre></td></tr></table></figure>

<p><a target="_blank" rel="noopener" href="https://docs.unrealengine.com/en-US/API/Runtime/Core/Internationalization/FRegexPattern/index.html">FRegexPattern手册</a></p>
<p>基本上能满足匹配，抓取之类的操作。</p>
<h3 id="7-2-FPaths"><a href="#7-2-FPaths" class="headerlink" title="7.2 FPaths"></a>7.2 FPaths</h3><p>获取游戏的根目录；判断文件是否存在；路径转换成绝对路径类似的功能。</p>
<p><a target="_blank" rel="noopener" href="https://docs.unrealengine.com/en-US/API/Runtime/Core/Misc/FPaths/index.html">FPaths官方文档</a></p>
<h3 id="7-3-XML-JSON"><a href="#7-3-XML-JSON" class="headerlink" title="7.3 XML/JSON"></a>7.3 XML/JSON</h3><p>FXmlFile/FastXML访问XML数据；</p>
<p>TJsonReaderFactory<TCHAR>/TJsonReader<TCHAR></p>
<p>FJsonSerializer::Deserialize 来加载json字符串。</p>
<h3 id="7-4-文件读写与访问"><a href="#7-4-文件读写与访问" class="headerlink" title="7.4 文件读写与访问"></a>7.4 文件读写与访问</h3><p>PlatformFileManager.h</p>
<p>里面提供了很多的操作文件的接口。</p>
<h3 id="7-5-GConfig"><a href="#7-5-GConfig" class="headerlink" title="7.5 GConfig"></a>7.5 GConfig</h3><p>是简单的将ini文件做了封装。可以指定ini文件，Section名称，Key，值。</p>
<h3 id="7-6-UE-LOG"><a href="#7-6-UE-LOG" class="headerlink" title="7.6 UE_LOG"></a>7.6 UE_LOG</h3><p>能支持Category方式的日志输出，日志级别也能支持。</p>
<h3 id="7-7-字符串处理"><a href="#7-7-字符串处理" class="headerlink" title="7.7 字符串处理"></a>7.7 字符串处理</h3><p>FName 无法修改的字符串，大小写不敏感。无论出现多少次，都是在字符串表里面只有一次出现。访问速度将会很快速。</p>
<p>FText 用于做显示的字符串，内置了本地化。</p>
<p>FString 能支持修改，消耗比上述的两种都要大。</p>
<h3 id="7-8-编译器相关技巧"><a href="#7-8-编译器相关技巧" class="headerlink" title="7.8 编译器相关技巧"></a>7.8 编译器相关技巧</h3><h4 id="7-8-1-废弃函数标记"><a href="#7-8-1-废弃函数标记" class="headerlink" title="7.8.1 废弃函数标记"></a>7.8.1 废弃函数标记</h4><p>编译器会检测出一些警告。</p>
<p>function Please update youre code to the new API before upgrading to the next release, otherwise your project will no longer compile.</p>
<h4 id="7-8-2-编译器指令实现跨平台"><a href="#7-8-2-编译器指令实现跨平台" class="headerlink" title="7.8.2 编译器指令实现跨平台"></a>7.8.2 编译器指令实现跨平台</h4><p>虚幻提供了FPlatformMisc，包含了大量平台相关的工具函数。</p>
<p>通过 typedef 切换编译期的平台切换。</p>
<p>在Linux里面有 FLinuxPlatformMisc 。切换的时候，将写这样的一句话。</p>
<p>typedef FLinuxPlatformMisc FPlatformMisc。</p>
<h3 id="7-9-Images"><a href="#7-9-Images" class="headerlink" title="7.9 Images"></a>7.9 Images</h3><p>ImagerWrapper 图片类型的抽象。</p>
<p>包含完整RGBA(red green blue alpha)数据的图片，是没有压缩过的，和格式没有关系，称为RawData原生的数据。</p>
<p>CompressedData会随着图片格式不同而不同。</p>
<p>ImagerWrapper是对这两个的封装。</p>
<h1 id="第二部分-虚幻引擎浅析"><a href="#第二部分-虚幻引擎浅析" class="headerlink" title="第二部分 虚幻引擎浅析"></a>第二部分 虚幻引擎浅析</h1><h2 id="第8章-模块机制"><a href="#第8章-模块机制" class="headerlink" title="第8章 模块机制"></a>第8章 模块机制</h2><h3 id="8-1-模块简介"><a href="#8-1-模块简介" class="headerlink" title="8.1 模块简介"></a>8.1 模块简介</h3><p>C++项目对外提供库的时候，需要管理include,lib目录。Debug/Release模式下的lib文件的管理。而且还需要编译不同平台下的库文件。</p>
<p>在UE3的时候，使用MakeFile来模拟模块，UE4为了彻底解决这些问题，使用了Unreal Build Tool。</p>
<h3 id="8-2-创建自己的模块"><a href="#8-2-创建自己的模块" class="headerlink" title="8.2 创建自己的模块"></a>8.2 创建自己的模块</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">模块名.Build.cs</span><br><span class="line">模块名.h</span><br><span class="line">模块名.cpp</span><br></pre></td></tr></table></figure>

<p>引入模块</p>
<p>工程名.Target.cs</p>
<p>SetupBinaries 方法里面调用 AddRange 函数将模块引入。</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">OutExtraModuleNames.<span class="built_in">AddRange</span>( <span class="keyword">new</span> string[]&#123;</span><br><span class="line">  <span class="string">&quot;pluginDev&quot;</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<p>插件名.uplugin</p>
<p>文件里面写了关于插件相关的信息。文件格式是json。</p>
<h3 id="8-3-虚幻引擎初始化模块加载顺序"><a href="#8-3-虚幻引擎初始化模块加载顺序" class="headerlink" title="8.3 虚幻引擎初始化模块加载顺序"></a>8.3 虚幻引擎初始化模块加载顺序</h3><p>本章就是列举了加载各种模块的顺序。</p>
<h3 id="8-4-UBT-UHT"><a href="#8-4-UBT-UHT" class="headerlink" title="8.4 UBT/UHT"></a>8.4 UBT/UHT</h3><p>UBT=Unreal Build Tool</p>
<p>UBT工作分为三个阶段：</p>
<ol>
<li>收集阶段，将环境变量、UE源码目录，工程目录信息收集起来；</li>
<li>参数解析阶段，将传入的命令行参数，确定自己生成的目标类型；</li>
<li>实际生成阶段，根据环境、参数，开始生成makefile，确定C++的各种目录位置。开始构建项目。</li>
</ol>
<p>UHT=Unreal Header Tool</p>
<p>UHT 配合实现了反射机制。</p>
<h2 id="第9章-重要合行系统简介"><a href="#第9章-重要合行系统简介" class="headerlink" title="第9章 重要合行系统简介"></a>第9章 重要合行系统简介</h2><h3 id="9-1-内存分配"><a href="#9-1-内存分配" class="headerlink" title="9.1 内存分配"></a>9.1 内存分配</h3><h4 id="9-1-1-Windows操作系统下的内存分配方案"><a href="#9-1-1-Windows操作系统下的内存分配方案" class="headerlink" title="9.1.1 Windows操作系统下的内存分配方案"></a>9.1.1 Windows操作系统下的内存分配方案</h4><p>主要通过</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">FMalloc* <span class="title">FWindowsPlatformMemory::BaseAllocator</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"><span class="meta">#<span class="meta-keyword">if</span> ENABLE_WIN_ALLOC_TRACKING</span></span></span><br><span class="line"><span class="function"><span class="meta">#<span class="meta-keyword">if</span> FORCE_ANSI_ALLOCATOR</span></span></span><br><span class="line"><span class="function"><span class="meta">#<span class="meta-keyword">elif</span> WITH_EDITORONLY_DATA </span></span></span><br></pre></td></tr></table></figure>

<p>一共提供了Mallo（ANSI）、Intel TBB，以及Binned内存分配器。</p>
<h3 id="9-2-引擎初始化过程"><a href="#9-2-引擎初始化过程" class="headerlink" title="9.2 引擎初始化过程"></a>9.2 引擎初始化过程</h3><p>初始化过程一共两个</p>
<p>PreInit/Init</p>
<p>PreInit支持输出参数，CmdLine。</p>
<p>设置好工作目录，游戏目录。</p>
<p>初始化随机种子。</p>
<p>设置输出标准设备。</p>
<p>初始游戏主线程。</p>
<p>会调用LoadCoreModules。CoreModules。</p>
<p>之后会将PreInitModules会被加载起来，启动之后调用AppInit函数。</p>
<p>Init</p>
<p>所有模块都加载到内存中，如果有PostEngineInit函数，就会调用。过程由IProjectManager完成。</p>
<p>主循环</p>
<p>虚幻引擎，有一个EngineTick()。在主循环中最好不要调用繁重的任务，否则将会把游戏卡住。</p>
<h3 id="9-3-并行与并发"><a href="#9-3-并行与并发" class="headerlink" title="9.3 并行与并发"></a>9.3 并行与并发</h3><p>测试代码一般文件名称为<code>模块名Test.cpp</code>。</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">DEFINE_LOG_CATEGORY_STATIC</span>(TestLog,Log,All);</span><br><span class="line"><span class="built_in">IMPLEMENT_SIMPLE_AUTOMATION_TEST</span>(FMultiThreadTest,<span class="string">&quot;MyTest.PublicTest</span></span><br><span class="line"><span class="string">  .MultiThreadIest&quot;</span>, EAutomationTestFlags::EditorContext |</span><br><span class="line">  EAutomationTestFlags::EngineFilter)</span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">FMultiThreadTest::RunTest</span><span class="params">(<span class="keyword">const</span> FString&amp; Parameters)</span></span></span><br></pre></td></tr></table></figure>

<p>通过UE4菜单栏。</p>
<p>Windows -&gt; General -&gt; Developer Tools -&gt; Session Frontend</p>
<p>打开“会话窗口”。</p>
<p>点击”Start Tests”按钮，就可以在Message Output里面输出的日志。</p>
<p>可以通过<code>FRunnableThread::Create(new FRunnableTestThread(0)</code>创建线程。就能开启多个线程。</p>
<p>Task Graph系统</p>
<p>将“指令”和“数据”封成一个包，然后交给Task Graph，Task Graph找到空闲的线程，去处理Task。</p>
<p>虚幻引擎Rama，写过对于Task Graph的描述。</p>
<p>Task Graph采用模板匹配，无需每个Task继承于指定的类，只要类将一些函数实现，就能让模板编译通过。<code>TGraphTask::CreateTask</code>。</p>
<p>std::thread</p>
<p>可以直接使用c++11的多线程。</p>
<p>线程同步</p>
<p>灵界区<code>FCriticalSection</code>。</p>
<p>也提供了<code>std::future</code>，<code>std::promise</code>,<code>TFuture</code>, <code>TPromise</code>。</p>
<p>多进程</p>
<p><code>Core.GenericPlatformProcess</code>可以看到<code>FGenericPlatformProcess</code>类的定义。可以通过管道进行数据交换。也将会返回<code>FProcHandle</code>子进程的句柄。</p>
<h2 id="第10章-对象模型"><a href="#第10章-对象模型" class="headerlink" title="第10章 对象模型"></a>第10章 对象模型</h2><p>本章主要讨论 UObject对象、组件对象和Actor对象。</p>
<h3 id="10-1-UObject"><a href="#10-1-UObject" class="headerlink" title="10.1 UObject"></a>10.1 UObject</h3><p>创建：通过<code>NewObject&lt;T&gt;</code>产生。<br>销毁：通过引擎的垃圾回收来销毁。</p>
<p>创建过程分为两个步骤：</p>
<ol>
<li>通过分配器将内存分配出来；</li>
</ol>
<p>使用<code>UObjectGlobals.GetPropertiesSize()</code>获取目标类的内存大小；</p>
<p>使用<code>FUObjectAllocator.AllocateUObject()</code>分配内存；</p>
<ol start="2">
<li>使用这块内存调用new方法，构建对象出来；</li>
</ol>
<p>使用<code>PlacemenetNew</code>将分配好的内存区域调用UObjectBase构造函数</p>
<p>对<code>UObject</code>提供UPackage存储读取逻辑。成员变量没有使用<code>UPROPERTY</code>宏标记，将不会序列化。</p>
<h1 id="注册虚幻引擎阅读权限"><a href="#注册虚幻引擎阅读权限" class="headerlink" title="注册虚幻引擎阅读权限"></a>注册虚幻引擎阅读权限</h1><p>可以登录到UE官网，开通github中，开源的UE源码阅读权限。</p>
<h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><ul>
<li>[1] <a target="_blank" rel="noopener" href="https://docs.unrealengine.com/zh-CN/index.html">UnrealEngine4官方文档</a></li>
<li>[2] <a target="_blank" rel="noopener" href="https://space.bilibili.com/138827797?spm_id_from=333.788.b_765f7570696e666f.2">虚幻引擎官方-B站</a></li>
<li>[3] <a target="_blank" rel="noopener" href="https://www.zhihu.com/org/xu-huan-yin-qing-24">虚幻引擎-知乎</a></li>
<li>[4] <a target="_blank" rel="noopener" href="https://github.com/EpicGames/UnrealEngine">虚幻引擎github</a></li>
<li>[5] <a target="_blank" rel="noopener" href="https://blog.csdn.net/m0_38106923/article/details/101937827">图片格式列举</a></li>
</ul>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://example.com/2021/01/14/2021/2021-01-14-UnrealEngine4/" data-id="ckrn3an7c001f20xw19ojch3u" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Game/" rel="tag">Game</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Unreal-Engine4/" rel="tag">Unreal Engine4</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-2021/2021-01-11-vscode" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2021/01/11/2021/2021-01-11-vscode/" class="article-date">
  <time datetime="2021-01-10T16:00:00.000Z" itemprop="datePublished">2021-01-11</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2021/01/11/2021/2021-01-11-vscode/">vscode笔记</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <p>记录vscode的使用技巧。</p>
<ul>
<li><a href="#%E5%85%89%E6%A0%87">光标</a><ul>
<li><a href="#%E5%A4%9A%E8%A1%8C%E7%BC%96%E8%BE%91">多行编辑</a></li>
</ul>
</li>
<li><a href="#%E6%8F%92%E4%BB%B6">插件</a><ul>
<li><a href="#%E5%B8%B8%E7%94%A8%E7%9A%84%E6%8F%92%E4%BB%B6">常用的插件</a></li>
<li><a href="#go%E8%AF%AD%E8%A8%80%E6%8F%92%E4%BB%B6">Go语言插件</a></li>
</ul>
</li>
<li><a href="#%E5%B7%A5%E4%BD%9C%E5%8C%BA%E9%97%B4">工作区间</a></li>
<li><a href="#c-%E8%B0%83%E8%AF%95%E5%AE%9E%E4%BE%8B">c++ 调试实例</a></li>
<li><a href="#%E5%AF%BC%E5%87%BAmarkdown%E6%95%B0%E5%AD%A6%E5%85%AC%E5%BC%8F%E6%97%A0%E7%94%A8">导出markdown数学公式无用</a></li>
<li><a href="#%E5%8F%82%E8%80%83">参考</a></li>
</ul>
<h1 id="光标"><a href="#光标" class="headerlink" title="光标"></a>光标</h1><h2 id="多行编辑"><a href="#多行编辑" class="headerlink" title="多行编辑"></a>多行编辑</h2><p>按住 alt 键，使用左键点击。按住 shift+alt 键，左键拖。</p>
<h1 id="插件"><a href="#插件" class="headerlink" title="插件"></a>插件</h1><h2 id="常用的插件"><a href="#常用的插件" class="headerlink" title="常用的插件"></a>常用的插件</h2><table>
<thead>
<tr>
<th align="left">分类</th>
<th align="left">插件名称</th>
<th align="left">说明</th>
<th align="left">备注</th>
</tr>
</thead>
<tbody><tr>
<td align="left">markdown</td>
<td align="left">Markdown All in One</td>
<td align="left"></td>
<td align="left"></td>
</tr>
<tr>
<td align="left"></td>
<td align="left">Markdown PDF</td>
<td align="left"></td>
<td align="left"></td>
</tr>
<tr>
<td align="left"></td>
<td align="left">Markdown Preview Enhanced</td>
<td align="left"></td>
<td align="left"></td>
</tr>
<tr>
<td align="left"></td>
<td align="left">Markdown Preview Mermaid Support</td>
<td align="left"></td>
<td align="left"></td>
</tr>
<tr>
<td align="left"></td>
<td align="left">markdown-formatter</td>
<td align="left"></td>
<td align="left"></td>
</tr>
<tr>
<td align="left"></td>
<td align="left">markdownlint</td>
<td align="left">自动检查合法性</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">Git</td>
<td align="left">GitLens</td>
<td align="left"></td>
<td align="left"></td>
</tr>
<tr>
<td align="left"></td>
<td align="left">Git History</td>
<td align="left"></td>
<td align="left"></td>
</tr>
<tr>
<td align="left"></td>
<td align="left">Git Graph</td>
<td align="left"></td>
<td align="left"></td>
</tr>
<tr>
<td align="left">主体</td>
<td align="left">Material Theme</td>
<td align="left"></td>
<td align="left"></td>
</tr>
<tr>
<td align="left"></td>
<td align="left">vscode-icons</td>
<td align="left"></td>
<td align="left"></td>
</tr>
<tr>
<td align="left"></td>
<td align="left">WakaTime</td>
<td align="left">统计代码习惯</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">远程工具</td>
<td align="left">Remote - Containers</td>
<td align="left"></td>
<td align="left"></td>
</tr>
<tr>
<td align="left"></td>
<td align="left">Remote - SSH</td>
<td align="left"></td>
<td align="left"></td>
</tr>
<tr>
<td align="left"></td>
<td align="left">Remote - SSH: Editing Configuration Files</td>
<td align="left"></td>
<td align="left"></td>
</tr>
<tr>
<td align="left"></td>
<td align="left">Remote - WSL</td>
<td align="left"></td>
<td align="left"></td>
</tr>
<tr>
<td align="left">Go</td>
<td align="left">Go for Visual Studio Code</td>
<td align="left"></td>
<td align="left"></td>
</tr>
</tbody></table>
<h2 id="Go语言插件"><a href="#Go语言插件" class="headerlink" title="Go语言插件"></a>Go语言插件</h2><p><a target="_blank" rel="noopener" href="https://imgchr.com/i/sRrPpQ"><img src="https://s3.ax1x.com/2021/01/20/sRrPpQ.png" alt="sRrPpQ.png"></a></p>
<p><a target="_blank" rel="noopener" href="https://imgchr.com/i/sRr9fg"><img src="https://s3.ax1x.com/2021/01/20/sRr9fg.png" alt="sRr9fg.png"></a></p>
<h1 id="工作区间"><a href="#工作区间" class="headerlink" title="工作区间"></a>工作区间</h1><p>目录清单</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">	<span class="attr">&quot;folders&quot;</span>: [</span><br><span class="line">		&#123;</span><br><span class="line">			<span class="attr">&quot;name&quot;</span>: <span class="string">&quot;bin&quot;</span>,</span><br><span class="line">			<span class="attr">&quot;path&quot;</span>: <span class="string">&quot;server\\bin&quot;</span></span><br><span class="line">    &#125;</span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>调试，附加进程</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">	<span class="attr">&quot;launch&quot;</span>: &#123;</span><br><span class="line">		<span class="attr">&quot;version&quot;</span>: <span class="string">&quot;0.2.0&quot;</span>,</span><br><span class="line">		<span class="attr">&quot;configurations&quot;</span>: [</span><br><span class="line">			&#123;</span><br><span class="line">				<span class="attr">&quot;name&quot;</span>: <span class="string">&quot;Attach to Process&quot;</span>,</span><br><span class="line">				<span class="attr">&quot;type&quot;</span>: <span class="string">&quot;go&quot;</span>,</span><br><span class="line">				<span class="attr">&quot;request&quot;</span>: <span class="string">&quot;attach&quot;</span>,</span><br><span class="line">				<span class="attr">&quot;mode&quot;</span>: <span class="string">&quot;local&quot;</span>,</span><br><span class="line">				<span class="comment">// &quot;remotePath&quot;: &quot;$&#123;workspaceFolder:bin&#125;\\Lobby.exe&quot;,</span></span><br><span class="line">				<span class="attr">&quot;presentation&quot;</span>: &#123;</span><br><span class="line">					<span class="attr">&quot;hidden&quot;</span>: <span class="literal">false</span>,</span><br><span class="line">					<span class="attr">&quot;group&quot;</span>: <span class="string">&quot;1&quot;</span>,</span><br><span class="line">					<span class="attr">&quot;order&quot;</span>: <span class="number">2</span></span><br><span class="line">				&#125;,</span><br><span class="line">				<span class="attr">&quot;processId&quot;</span>: <span class="number">17984</span></span><br><span class="line">      &#125;,</span><br><span class="line">      &#123;</span><br><span class="line">				<span class="attr">&quot;name&quot;</span>: <span class="string">&quot;Login.exe&quot;</span>,</span><br><span class="line">				<span class="attr">&quot;type&quot;</span>: <span class="string">&quot;go&quot;</span>,</span><br><span class="line">				<span class="attr">&quot;request&quot;</span>: <span class="string">&quot;launch&quot;</span>,</span><br><span class="line">				<span class="attr">&quot;mode&quot;</span>: <span class="string">&quot;exec&quot;</span>,</span><br><span class="line">				<span class="attr">&quot;program&quot;</span>: <span class="string">&quot;$&#123;workspaceFolder:bin&#125;\\Login.exe&quot;</span>,</span><br><span class="line">				<span class="attr">&quot;env&quot;</span>: &#123;&#125;,</span><br><span class="line">				<span class="attr">&quot;args&quot;</span>: []</span><br><span class="line">      &#125;</span><br><span class="line">    ]</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>组合节点</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">		<span class="attr">&quot;compounds&quot;</span>: [</span><br><span class="line">			&#123;</span><br><span class="line">				<span class="attr">&quot;name&quot;</span>: <span class="string">&quot;Build/RunAll&quot;</span>,</span><br><span class="line">				<span class="attr">&quot;configurations&quot;</span>: [</span><br><span class="line">					<span class="comment">// &quot;Login.exe&quot;,</span></span><br><span class="line">					<span class="string">&quot;Gateway.exe&quot;</span>,</span><br><span class="line">					<span class="string">&quot;DBServer.exe&quot;</span>,</span><br><span class="line">					<span class="string">&quot;Lobby.exe&quot;</span>,</span><br><span class="line">					<span class="string">&quot;Scene.exe&quot;</span>,</span><br><span class="line">					<span class="string">&quot;Matcher.exe&quot;</span>,</span><br><span class="line">					<span class="string">&quot;Level.exe&quot;</span></span><br><span class="line">				],</span><br><span class="line">				<span class="attr">&quot;presentation&quot;</span>: &#123;</span><br><span class="line">					<span class="attr">&quot;hidden&quot;</span>: <span class="literal">false</span>,</span><br><span class="line">					<span class="attr">&quot;group&quot;</span>: <span class="string">&quot;1&quot;</span>,</span><br><span class="line">					<span class="attr">&quot;order&quot;</span>: <span class="number">1</span></span><br><span class="line">				&#125;,</span><br><span class="line">				<span class="attr">&quot;preLaunchTask&quot;</span>: <span class="string">&quot;buildall&quot;</span>,</span><br><span class="line">				<span class="attr">&quot;stopAll&quot;</span>: <span class="literal">true</span>,</span><br><span class="line">      &#125;</span><br><span class="line">    ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>任务节点</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">	<span class="attr">&quot;tasks&quot;</span>: &#123;</span><br><span class="line">		<span class="attr">&quot;version&quot;</span>: <span class="string">&quot;2.0.0&quot;</span>,</span><br><span class="line">		<span class="attr">&quot;tasks&quot;</span>: [</span><br><span class="line">			&#123;</span><br><span class="line">				<span class="attr">&quot;label&quot;</span>: <span class="string">&quot;buildall&quot;</span>,</span><br><span class="line">				<span class="attr">&quot;type&quot;</span>: <span class="string">&quot;shell&quot;</span>,</span><br><span class="line">				<span class="attr">&quot;command&quot;</span>: <span class="string">&quot;go&quot;</span>,</span><br><span class="line">				<span class="attr">&quot;args&quot;</span>: [</span><br><span class="line">					<span class="string">&quot;build&quot;</span>,</span><br><span class="line">					<span class="string">&quot;-gcflags&quot;</span>,</span><br><span class="line">					<span class="string">&quot;&#x27;-N -l&#x27;&quot;</span>,</span><br><span class="line">					<span class="comment">// &quot;-race&quot;,</span></span><br><span class="line">					<span class="string">&quot;-o&quot;</span>,</span><br><span class="line">					<span class="string">&quot;$&#123;workspaceFolder:bin&#125;&quot;</span>,</span><br><span class="line">					<span class="string">&quot;./...&quot;</span></span><br><span class="line">				],</span><br><span class="line">				<span class="attr">&quot;options&quot;</span>: &#123;</span><br><span class="line">					<span class="attr">&quot;cwd&quot;</span>: <span class="string">&quot;$&#123;workspaceFolder:src&#125;&quot;</span></span><br><span class="line">				&#125;,</span><br><span class="line">				<span class="attr">&quot;problemMatcher&quot;</span>: [],</span><br><span class="line">				<span class="attr">&quot;group&quot;</span>: &#123;</span><br><span class="line">					<span class="attr">&quot;kind&quot;</span>: <span class="string">&quot;build&quot;</span>,</span><br><span class="line">					<span class="attr">&quot;isDefault&quot;</span>: <span class="literal">true</span></span><br><span class="line">				&#125;</span><br><span class="line">      &#125;</span><br><span class="line">    ]</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h1 id="c-调试实例"><a href="#c-调试实例" class="headerlink" title="c++ 调试实例"></a>c++ 调试实例</h1><p><code>launch.json</code>实例。已经在windows 10 WSL 1.0里面尝试过了；</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">    <span class="comment">// 使用 IntelliSense 了解相关属性。 </span></span><br><span class="line">    <span class="comment">// 悬停以查看现有属性的描述。</span></span><br><span class="line">    <span class="comment">// 欲了解更多信息，请访问: https://go.microsoft.com/fwlink/?linkid=830387</span></span><br><span class="line">    <span class="attr">&quot;version&quot;</span>: <span class="string">&quot;0.2.0&quot;</span>,</span><br><span class="line">    <span class="attr">&quot;configurations&quot;</span>: [</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="attr">&quot;name&quot;</span>: <span class="string">&quot;启动sentinel&quot;</span>,</span><br><span class="line">            <span class="attr">&quot;type&quot;</span>: <span class="string">&quot;cppdbg&quot;</span>,</span><br><span class="line">            <span class="attr">&quot;request&quot;</span>: <span class="string">&quot;launch&quot;</span>,</span><br><span class="line">            <span class="attr">&quot;program&quot;</span>: <span class="string">&quot;$&#123;workspaceFolder&#125;/octopus_svr/build/sentinel/sentinel&quot;</span>,</span><br><span class="line">            <span class="attr">&quot;args&quot;</span>: [],</span><br><span class="line">            <span class="attr">&quot;stopAtEntry&quot;</span>: <span class="literal">false</span>,</span><br><span class="line">            <span class="attr">&quot;cwd&quot;</span>: <span class="string">&quot;$&#123;workspaceFolder&#125;/octopus_svr/build/sentinel&quot;</span>,</span><br><span class="line">            <span class="attr">&quot;environment&quot;</span>: [],</span><br><span class="line">            <span class="attr">&quot;externalConsole&quot;</span>: <span class="literal">false</span>,</span><br><span class="line">            <span class="attr">&quot;MIMode&quot;</span>: <span class="string">&quot;gdb&quot;</span>,</span><br><span class="line">            <span class="attr">&quot;setupCommands&quot;</span>: [</span><br><span class="line">                &#123;</span><br><span class="line">                    <span class="attr">&quot;description&quot;</span>: <span class="string">&quot;为 gdb 启用整齐打印&quot;</span>,</span><br><span class="line">                    <span class="attr">&quot;text&quot;</span>: <span class="string">&quot;-enable-pretty-printing&quot;</span>,</span><br><span class="line">                    <span class="attr">&quot;ignoreFailures&quot;</span>: <span class="literal">true</span></span><br><span class="line">                &#125;</span><br><span class="line">            ]</span><br><span class="line">        &#125;</span><br><span class="line">    ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h1 id="导出markdown数学公式无用"><a href="#导出markdown数学公式无用" class="headerlink" title="导出markdown数学公式无用"></a>导出markdown数学公式无用</h1><table>
<thead>
<tr>
<th align="left">操作系统</th>
<th align="left">安装路径</th>
</tr>
</thead>
<tbody><tr>
<td align="left">windows</td>
<td align="left"><code>%USERPROFILE%\.vscode\extensions</code></td>
</tr>
<tr>
<td align="left">macOS</td>
<td align="left"><code>~/.vscode/extensions</code></td>
</tr>
<tr>
<td align="left">Linux</td>
<td align="left"><code>~/.vscode/extensions</code></td>
</tr>
</tbody></table>
<p>找到插件目录中：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">.vscode/extensions/yzane.markdown-pdf-1.4.1/template/template.html</span><br><span class="line">在body节点内增加这两行代码；</span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML&quot;</span> <span class="attr">type</span>=<span class="string">&quot;text/javascript&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span> <span class="attr">type</span>=<span class="string">&quot;text/x-mathjax-config&quot;</span>&gt;</span><span class="javascript"></span></span><br><span class="line"><span class="javascript">    MathJax.Hub.Config(&#123;</span></span><br><span class="line"><span class="javascript">        <span class="attr">tex2jax</span>: &#123;</span></span><br><span class="line"><span class="javascript">        <span class="attr">skipTags</span>: [<span class="string">&#x27;script&#x27;</span>, <span class="string">&#x27;noscript&#x27;</span>, <span class="string">&#x27;style&#x27;</span>, <span class="string">&#x27;textarea&#x27;</span>, <span class="string">&#x27;pre&#x27;</span>],</span></span><br><span class="line"><span class="javascript">        <span class="attr">inlineMath</span>: [ [<span class="string">&#x27;$&#x27;</span>,<span class="string">&#x27;$&#x27;</span>], [<span class="string">&quot;\\(&quot;</span>,<span class="string">&quot;\\)&quot;</span>] ],</span></span><br><span class="line"><span class="javascript">        <span class="attr">displayMath</span>: [ [<span class="string">&#x27;$$&#x27;</span>,<span class="string">&#x27;$$&#x27;</span>], [<span class="string">&quot;\\[&quot;</span>,<span class="string">&quot;\\]&quot;</span>] ]</span></span><br><span class="line"><span class="javascript">        &#125;</span></span><br><span class="line"><span class="javascript">    &#125;);</span></span><br><span class="line"><span class="javascript">    </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>


<h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><ul>
<li>[1] <a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/40417719">30个极大提高开发效率的VSCode插件</a></li>
<li>[2] <a target="_blank" rel="noopener" href="https://code.visualstudio.com/docs/getstarted/settings">官方用户工作区设置文档</a></li>
</ul>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://example.com/2021/01/11/2021/2021-01-11-vscode/" data-id="ckrn3an7a001b20xwea5p1h1f" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/vscode/" rel="tag">vscode</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-2020/2020-12-29-3d数学" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2020/12/29/2020/2020-12-29-3d%E6%95%B0%E5%AD%A6/" class="article-date">
  <time datetime="2020-12-28T16:00:00.000Z" itemprop="datePublished">2020-12-29</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2020/12/29/2020/2020-12-29-3d%E6%95%B0%E5%AD%A6/">3d数学</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <p>在游戏开发中，需要使用到向量，三角函数之类的知识。先学会里面的概念，后续应用才会容易制作。</p>
<ul>
<li><a href="#3d%E6%95%B0%E5%AD%A6">3d数学</a><ul>
<li><a href="#1%E7%AC%9B%E5%8D%A1%E5%B0%94%E5%9D%90%E6%A0%87%E7%B3%BBcartesian">1.笛卡尔坐标系（Cartesian）</a></li>
<li><a href="#2%E4%B8%89%E8%A7%92%E5%AD%A6">2.三角学</a><ul>
<li><a href="#1%E7%9B%B4%E8%A7%92%E4%B8%89%E8%A7%92%E5%BD%A2%E4%B8%89%E8%A7%92%E5%87%BD%E6%95%B0%E6%A6%82%E5%BF%B5">1.直角三角形三角函数概念</a><ul>
<li><a href="#%E4%BD%99%E5%BC%A6-cosine">余弦 cosine</a></li>
<li><a href="#%E6%AD%A3%E5%BC%A6-sine">正弦 sine</a></li>
<li><a href="#%E5%89%B2%E7%BA%BF-secant">割线 secant</a></li>
<li><a href="#%E4%BD%99%E5%89%B2-cosecant">余割 cosecant</a></li>
<li><a href="#%E5%88%87%E7%BA%BF-tangent">切线 tangent</a></li>
<li><a href="#%E4%BD%99%E5%88%87-cotangent">余切 cotangent</a></li>
<li><a href="#%E5%8F%8D%E5%88%87%E7%BA%BF%E5%87%BD%E6%95%B0">反切线函数</a></li>
</ul>
</li>
<li><a href="#2%E8%A7%92%E5%BA%A6%E5%BC%A7%E5%BA%A6">2.角度弧度</a></li>
<li><a href="#3%E4%B8%89%E8%A7%92%E6%81%92%E7%AD%89%E5%BC%8F">3.三角恒等式</a><ul>
<li><a href="#%E5%AF%B9%E7%A7%B0%E6%80%A7%E6%81%92%E7%AD%89%E5%BC%8F">对称性恒等式</a></li>
<li><a href="#%E6%AF%95%E8%BE%BE%E5%93%A5%E6%8B%89%E6%96%AF%E6%81%92%E7%AD%89%E5%BC%8F">毕达哥拉斯恒等式</a></li>
<li><a href="#%E5%92%8C%E6%88%96%E5%B7%AE%E6%81%92%E7%AD%89%E5%BC%8F">和或差恒等式</a></li>
<li><a href="#%E7%AD%89%E8%85%B0%E4%B8%89%E8%A7%92%E5%BD%A2%E6%81%92%E7%AD%89%E5%BC%8F">等腰三角形恒等式</a></li>
<li><a href="#%E6%AD%A3%E5%BC%A6%E4%BD%99%E5%BC%A6%E5%AE%9A%E7%90%86">正弦、余弦定理</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#3%E5%90%91%E9%87%8F">3.向量</a><ul>
<li><a href="#1%E5%8A%A0%E6%B3%95">1.加法</a></li>
<li><a href="#2%E5%87%8F%E6%B3%95">2.减法</a></li>
<li><a href="#3%E5%90%91%E9%87%8F%E4%B8%8E%E6%A0%87%E9%87%8F%E4%B9%98">3.向量与标量乘</a></li>
<li><a href="#4%E8%8E%B7%E5%8F%96%E9%95%BF%E5%BA%A6">4.获取长度</a></li>
<li><a href="#5normalized">5.normalized</a></li>
<li><a href="#6-dot-product">6. Dot Product</a></li>
<li><a href="#7cross-produce">7.cross produce</a></li>
<li><a href="#8%E8%8E%B7%E5%8F%96%E8%A7%92%E5%BA%A6">8.获取角度</a></li>
<li><a href="#9%E5%B8%B8%E7%94%A8%E5%87%BD%E6%95%B0">9.常用函数</a></li>
</ul>
</li>
<li><a href="#%E5%AE%9E%E4%BE%8B">实例</a><ul>
<li><a href="#1%E8%AE%A1%E7%AE%97%E5%9B%B4%E7%BB%95role%E7%9A%84%E6%80%AA%E7%89%A9">1.计算围绕role的怪物</a></li>
<li><a href="#2%E8%AE%A1%E7%AE%97%E5%9B%AD%E5%A4%96%E5%88%87%E7%BA%BF">2.计算园外切线</a></li>
<li><a href="#3%E8%AE%A1%E7%AE%97%E6%9F%90%E4%B8%AA%E7%82%B9%E6%98%AF%E5%90%A6%E4%B8%BA%E4%B8%89%E8%A7%92%E5%BD%A2%E5%86%85">3.计算某个点是否为三角形内</a></li>
<li><a href="#4%E8%AE%A1%E7%AE%97%E7%9F%A9%E5%BD%A2%E5%86%85%E7%9A%84%E4%B8%80%E7%82%B9">4.计算矩形内的一点</a></li>
<li><a href="#5%E8%AE%A1%E7%AE%97%E4%B8%A4%E4%B8%AA%E8%A7%92%E5%BA%A6%E7%9B%B8%E5%B7%AE">5.计算两个角度相差</a></li>
<li><a href="#6%E8%A7%92%E5%BA%A6%E6%A0%BC%E5%BC%8F%E5%8C%96">6.角度格式化</a></li>
<li><a href="#7-%E8%AE%A1%E7%AE%97%E7%BA%BF%E6%AE%B5%E4%B8%8E%E5%9C%86%E7%9B%B8%E4%BA%A4">7. 计算线段与圆相交</a></li>
</ul>
</li>
<li><a href="#4%E7%9F%A9%E9%98%B5">4.矩阵</a><ul>
<li><a href="#1%E6%A6%82%E5%BF%B5">1.概念</a></li>
<li><a href="#2%E7%9F%A9%E9%98%B5%E8%BF%90%E7%AE%97">2.矩阵运算</a><ul>
<li><a href="#1%E8%BD%AC%E7%BD%AE">1.转置</a></li>
<li><a href="#2%E7%9F%A9%E9%98%B5%E4%B8%8E%E6%A0%87%E9%87%8F%E4%B9%98">2.矩阵与标量乘</a></li>
<li><a href="#3%E7%9F%A9%E9%98%B5%E4%B9%98%E6%B3%95">3.矩阵乘法</a></li>
<li><a href="#4%E5%85%8B%E7%BD%97%E5%86%85%E5%85%8B%E7%A7%AFkronecker-product">4.克罗内克积（Kronecker Product）</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#6%E6%AC%A7%E6%8B%89%E8%A7%92">6.欧拉角</a><ul>
<li><a href="#4%E4%B8%87%E5%90%91%E8%8A%82%E6%AD%BB%E9%94%81">4.万向节死锁</a></li>
<li><a href="#2%E6%AC%A7%E6%8B%89%E6%81%92%E7%AD%89%E5%BC%8F">2.欧拉恒等式</a></li>
</ul>
</li>
<li><a href="#5%E5%9B%9B%E5%85%83%E6%95%B0">5.四元数</a><ul>
<li><a href="#1%E6%A6%82%E8%BF%B0">1.概述</a></li>
</ul>
</li>
<li><a href="#%E5%8F%82%E8%80%83">参考</a></li>
</ul>
</li>
</ul>
<h1 id="3d数学"><a href="#3d数学" class="headerlink" title="3d数学"></a>3d数学</h1><h2 id="1-笛卡尔坐标系（Cartesian）"><a href="#1-笛卡尔坐标系（Cartesian）" class="headerlink" title="1.笛卡尔坐标系（Cartesian）"></a>1.笛卡尔坐标系（Cartesian）</h2><p>2d坐标系：x,y</p>
<p>3d坐标系：x,y,z</p>
<p>在3d坐标系里面有左手坐标系和右手坐标系。这个可能对人来说有直观认知上的区别，其实是不相悖。</p>
<p>右手坐标系</p>
<p><a target="_blank" rel="noopener" href="https://imgchr.com/i/sro8jH"><img src="https://s3.ax1x.com/2021/01/17/sro8jH.jpg" alt="sro8jH.jpg"></a></p>
<p>左手坐标系</p>
<p><a target="_blank" rel="noopener" href="https://imgchr.com/i/sro3ge"><img src="https://s3.ax1x.com/2021/01/17/sro3ge.jpg" alt="sro3ge.jpg"></a></p>
<p>附带：</p>
<p>极坐标系（polar coordinates）是指在平面内由极点、极轴和极径组成的坐标系。在平面上取定一点O，称为极点。从O出发引一条射线Ox，称为极轴。再取定一个单位长度，通常规定角度取逆时针方向为正。这样，平面上任一点P的位置就可以用线段OP的长度ρ以及从Ox到OP的角度θ来确定，有序数对（ρ，θ）就称为P点的极坐标，记为P（ρ，θ）；ρ称为P点的极径，θ称为P点的极角。</p>
<p>极坐标系用于定位和导航。极坐标通常被用于导航，作为旅行的目的地或方向可以作为从所考虑的物体的距离和角度。</p>
<h2 id="2-三角学"><a href="#2-三角学" class="headerlink" title="2.三角学"></a>2.三角学</h2><p>这块的知识属于初等函数。初等函数包含的有：</p>
<p>幂函数、指数函数、对数函数、三角函数、反三角函数、有理运算（加减乘除，有理数次乘方、有理数次开放）、有限次函数复合。</p>
<h3 id="1-直角三角形三角函数概念"><a href="#1-直角三角形三角函数概念" class="headerlink" title="1.直角三角形三角函数概念"></a>1.直角三角形三角函数概念</h3><p><a target="_blank" rel="noopener" href="https://imgchr.com/i/sr7VT1"><img src="https://s3.ax1x.com/2021/01/17/sr7VT1.jpg" alt="sr7VT1.jpg"></a></p>
<ul>
<li>对边 Opposite（opp） y</li>
<li>邻边 Adjacent（adj） x</li>
<li>斜边 Hypotenuse（hyp） r</li>
</ul>
<p>勾股定理（毕达哥拉斯定理）</p>
<p>$$r=\sqrt{x^2+y^2}$$</p>
<p>$$5=\sqrt{3^2+4^2}$$</p>
<p>$$∠A 为\theta$$</p>
<h4 id="余弦-cosine"><a href="#余弦-cosine" class="headerlink" title="余弦 cosine"></a>余弦 cosine</h4><p>邻边比斜边。</p>
<p>$$cos(\theta) = \frac{x}{r}$$</p>
<p><a target="_blank" rel="noopener" href="https://imgchr.com/i/rqrTSO"><img src="https://s3.ax1x.com/2020/12/30/rqrTSO.png" alt="rqrTSO.png"></a></p>
<h4 id="正弦-sine"><a href="#正弦-sine" class="headerlink" title="正弦 sine"></a>正弦 sine</h4><p>对边比斜边。</p>
<p>$$sin(\theta) = \frac{y}{r}$$</p>
<p><a target="_blank" rel="noopener" href="https://imgchr.com/i/rqrIfK"><img src="https://s3.ax1x.com/2020/12/30/rqrIfK.png" alt="rqrIfK.png"></a></p>
<p><strong>正弦余弦背诵的时候，按照字母排序，x &lt; y ，cos &lt; sin。</strong></p>
<h4 id="割线-secant"><a href="#割线-secant" class="headerlink" title="割线 secant"></a>割线 secant</h4><p>$\sec(\theta)=\frac{1}{\cos(\theta)}$</p>
<p>$\sec(\theta)=\frac{r}{x}$</p>
<h4 id="余割-cosecant"><a href="#余割-cosecant" class="headerlink" title="余割 cosecant"></a>余割 cosecant</h4><p>$\csc(\theta)=\frac{1}{\sin(\theta)}$</p>
<p>$\csc(\theta)=\frac{r}{y}$</p>
<h4 id="切线-tangent"><a href="#切线-tangent" class="headerlink" title="切线 tangent"></a>切线 tangent</h4><p>对边比邻边。</p>
<p>$\tan(\theta)=\frac{\sin(\theta)}{\cos(\theta)}$</p>
<p>$$\tan(\theta) = \frac{y}{x}$$</p>
<h4 id="余切-cotangent"><a href="#余切-cotangent" class="headerlink" title="余切 cotangent"></a>余切 cotangent</h4><p>邻边比对边。</p>
<p>$$\cot(\theta) = \frac{1}{\tan(\theta)}=\frac{\cos(\theta)}{sin(\theta)}$$</p>
<p>$$\cot(\theta) = \frac{x}{y}$$</p>
<h4 id="反切线函数"><a href="#反切线函数" class="headerlink" title="反切线函数"></a>反切线函数</h4><p>反切线函数的反函数 arctangent</p>
<p>$$\arctan(\tan(\theta)) = \theta$$</p>
<h3 id="2-角度弧度"><a href="#2-角度弧度" class="headerlink" title="2.角度弧度"></a>2.角度弧度</h3><p>半径为1的园，全弧长为2$\pi$r。</p>
<p>$$radian=degree*(\pi/180)$$</p>
<p>$$degree = radian*(180/\pi)$$</p>
<p>角度是两条线段的夹角，弧度是两条线段和园相交的点，在圆弧上走过的距离。</p>
<p><a target="_blank" rel="noopener" href="https://imgchr.com/i/sr7ghV"><img src="https://s3.ax1x.com/2021/01/17/sr7ghV.jpg" alt="sr7ghV.jpg"></a></p>
<p>角度使用360°，原因来自于日历。波斯日历就是360天。360能被整除的数字（不算自己和1）有22个数字。</p>
<h3 id="3-三角恒等式"><a href="#3-三角恒等式" class="headerlink" title="3.三角恒等式"></a>3.三角恒等式</h3><h4 id="对称性恒等式"><a href="#对称性恒等式" class="headerlink" title="对称性恒等式"></a>对称性恒等式</h4><p>$$\sin(-\theta)=-\sin(\theta),    cos(-\theta)=cos(\theta),\tan(-\theta)=-tan(-\theta),\<br>\sin(\frac{\pi}{2}-\theta)=\cos(\theta),    \cos(\frac{\pi}{2}-\theta)=\sin(\theta),\tan(\frac{\pi}{2}-\theta)=\cot(\theta)$$</p>
<h4 id="毕达哥拉斯恒等式"><a href="#毕达哥拉斯恒等式" class="headerlink" title="毕达哥拉斯恒等式"></a>毕达哥拉斯恒等式</h4><p>这是由勾股定理推算出来的。</p>
<p>$$\sin^2\theta+\cos^2\theta=1,    1+\tan^2\theta=\sec^2\theta,    1+\cot^2\theta=\csc^2\theta$$</p>
<h4 id="和或差恒等式"><a href="#和或差恒等式" class="headerlink" title="和或差恒等式"></a>和或差恒等式</h4><p>$$\sin(a+b)=\sin(a)\cos(b)+\cos(a)+\sin(b)\<br>\sin(a-b)=\sin(a)\cos(b)-\cos(a)+\sin(b)\<br>\cos(a+b)=\cos(a)\cos(b)-\sin(a)+\sin(b)\<br>\cos(a-b)=\cos(a)\cos(b)+\sin(a)+\sin(b)\<br>\tan(a-b)=\frac{\tan(a)+\tan(b)}{1-\tan(a)\tan(b)}\<br>\tan(a-b)=\frac{\tan(a)-\tan(b)}{1+\tan(a)\tan(b)}<br>$$</p>
<p>背诵的时候，只需要记住一半，其他的是符号相反。</p>
<h4 id="等腰三角形恒等式"><a href="#等腰三角形恒等式" class="headerlink" title="等腰三角形恒等式"></a>等腰三角形恒等式</h4><p>其实就是<strong>和或差恒等式</strong>公式里面a=b的情况下，推导出来的。</p>
<p>$$\sin(2\theta)=2\sin(\theta)\cos(\theta)$$</p>
<p>在阅读Detour源码里面有这样的应用。里面将会读取一个sin cos的一半做乘法。</p>
<p>$$\cos(2\theta)=\cos^2(\theta)-\sin^2\theta=2\cos^2(\theta)-1=1-2\sin^2(\theta)$$</p>
<p>$$\tan(2\theta)=\frac{2\tan(\theta)}{1-\tan^2\theta}$$</p>
<h4 id="正弦、余弦定理"><a href="#正弦、余弦定理" class="headerlink" title="正弦、余弦定理"></a>正弦、余弦定理</h4><p>如果已知边长，已知角度，需要推算出未知边长度，就需要使用这个定理。而且是任意三角形。</p>
<ul>
<li>正弦定理</li>
</ul>
<p>$$\frac{\sin(A)}{a}=\frac{\sin(B)}{b}=\frac{\sin(C)}{c}$$</p>
<ul>
<li>余弦定理</li>
</ul>
<p>$$a^2=b^2+c^2-2bc\cos(A)\<br>b^2=a^2+c^2-2ac\cos(B)\<br>c^2=b^2+b^2-2ab\cos(C)<br>$$</p>
<p><a target="_blank" rel="noopener" href="https://imgtu.com/i/6kRlCD"><img src="https://s3.ax1x.com/2021/03/02/6kRlCD.png" alt="6kRlCD.png"></a></p>
<h2 id="3-向量"><a href="#3-向量" class="headerlink" title="3.向量"></a>3.向量</h2><p>向量计算应用于游戏中来计算位置，里面和三角函数也有关系。</p>
<p>向量和标量不一样，</p>
<p><strong>标量</strong>(scale)只表示数值大小；</p>
<p><strong>向量</strong>(矢量、vector)包含方向和数值大小。</p>
<p>举例：</p>
<p>速度、位移是向量</p>
<p>速率、长度是标量</p>
<p><strong>零向量</strong>是指的长度为0，无方向的向量。</p>
<h3 id="1-加法"><a href="#1-加法" class="headerlink" title="1.加法"></a>1.加法</h3><p>将两个向量拼接成平行四边形，对角向量就是加法的结果。两个相同的向量相加，等于将向量长度增加一倍。</p>
<p>$$\vec{u} + \vec{v} = \vec{a} $$</p>
<p><a target="_blank" rel="noopener" href="https://imgchr.com/i/snVdeS"><img src="https://s3.ax1x.com/2021/01/08/snVdeS.png" alt="snVdeS.png"></a></p>
<h3 id="2-减法"><a href="#2-减法" class="headerlink" title="2.减法"></a>2.减法</h3><p>u向量-v向量，就是指的从u向量目的点指向v向量目标点</p>
<p>$$\vec{v} - \vec{u} = \vec{w} = \vec{a}$$</p>
<p><a target="_blank" rel="noopener" href="https://imgchr.com/i/snVUL8"><img src="https://s3.ax1x.com/2021/01/08/snVUL8.png" alt="snVUL8.png"></a></p>
<h3 id="3-向量与标量乘"><a href="#3-向量与标量乘" class="headerlink" title="3.向量与标量乘"></a>3.向量与标量乘</h3><p>向量与标量乘法，将向量按照某个长度缩放，一般用于单位向量向前行进、缩回多少距离。</p>
<h3 id="4-获取长度"><a href="#4-获取长度" class="headerlink" title="4.获取长度"></a>4.获取长度</h3><p>获取向量从开始到结束的距离。从向量得到标量。利用勾股定理，向量记录的就是直角三角形斜边在x,y轴上的投影长度，斜边长度就是x,y的平方和的开方。</p>
<p>数学公式里面向量长度使用双竖线引用。</p>
<p>$$\left||\vec{v}\right||=\sqrt{a^2+b^2}$$</p>
<h3 id="5-normalized"><a href="#5-normalized" class="headerlink" title="5.normalized"></a>5.normalized</h3><p>归一化需要将向量长度计算出来，然后将向量在各个维度的分量都除以长度。这样就能得到一个单位向量。归一化用一条竖线。</p>
<p>$$\vec{v}_{norm} = \frac{\vec{v}} {\left||\vec{v}\right||}$$</p>
<p>单位化的向量分量的几何意义</p>
<p>$$x=\cos(\theta)$$</p>
<p>$$y=\sin(\theta)$$</p>
<p>这个特性将会应用于计算位置。</p>
<h3 id="6-Dot-Product"><a href="#6-Dot-Product" class="headerlink" title="6. Dot Product"></a>6. Dot Product</h3><p>$$\cos\theta=\frac{\vec{u} \cdot \vec{v}} {\left||\vec{u}\right||\left||\vec{v}\right||}$$</p>
<p>点乘能计算两向量的夹角的cos值。cos有一个特点，在取值±90°的值域都是&gt;0。在游戏中，这种计算能很快判断一个怪物是否在玩家身后。这个函数不能判断左右，但是能判断前后。</p>
<h3 id="7-cross-produce"><a href="#7-cross-produce" class="headerlink" title="7.cross produce"></a>7.cross produce</h3><p>$$\sin\theta=\frac{\vec{u} \times \vec{v}} {\left||\vec{u}\right||\left||\vec{v}\right||}$$</p>
<p>叉乘用于算左右。sin有个特点，取值在0~179°都是&gt;0。用找个特点能判定向量是在自己的左边还是右边。</p>
<p>叉乘需要有3个维度才有意义。</p>
<p>$$\vec{u}\times\vec{v}=\left|\vec{u}\right|\left|\vec{v}\right|\sin(\theta)n$$</p>
<p>u叉乘v之后结果是sin*u、v向量的分量。n就是垂直于u、v构成平面的垂直法线向量。</p>
<p>3D向量叉乘</p>
<p>$$\left[\begin{matrix}<br>  x_1\<br>  y_1\<br>  z_1<br>\end{matrix}\right] \times \left[\begin{matrix}<br>  x_2\<br>  y_2\<br>  z_2<br>\end{matrix}\right] = \left[\begin{matrix}<br>  y_1z_2-z_1y_2\<br>  z_1x_2-x_1z_2\<br>  x_1y_2-y_1x_2<br>\end{matrix}\right]$$</p>
<p>2D向量叉乘</p>
<p>$$\left[\begin{matrix}<br>  x_1\<br>  y_1<br>\end{matrix}\right] \times \left[\begin{matrix}<br>  x_2\<br>  y_2<br>\end{matrix}\right] =  x_1y_2-x_2y_1 $$</p>
<h3 id="8-获取角度"><a href="#8-获取角度" class="headerlink" title="8.获取角度"></a>8.获取角度</h3><p>将向量转换成弧度，向量无需归一化。<a target="_blank" rel="noopener" href="https://baike.baidu.com/item/atan2/10931300?fr=aladdin">百度百科atan2</a></p>
<p>$$\angle\theta=\arctan(y,x)$$</p>
<p>$$\arctan(y,x)=\begin{cases}<br>\arctan(\frac{y}{x}), x &gt;0\<br>\arctan(\frac{y}{x}) + \pi, y\geq 0, x\le 0<br>\end{cases}$$</p>
<h3 id="9-常用函数"><a href="#9-常用函数" class="headerlink" title="9.常用函数"></a>9.常用函数</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="comment">// 将弧度转换成角度</span></span><br><span class="line"><span class="function"><span class="keyword">float</span> <span class="title">radian2angle</span><span class="params">(<span class="keyword">float</span> radian)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> radian * (<span class="number">180.0f</span> / mathfu::kPi);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 将角度转换成弧度</span></span><br><span class="line"><span class="function"><span class="keyword">float</span> <span class="title">angle2radian</span><span class="params">(<span class="keyword">float</span> angle)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> angle * (mathfu::kPi / <span class="number">180.0f</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 将向量转换成角度</span></span><br><span class="line"><span class="function"><span class="keyword">float</span> <span class="title">vector2angle</span><span class="params">(mathfu::Vector&lt;<span class="keyword">float</span>, <span class="number">2</span>&gt; a)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">radian2angle</span>(std::<span class="built_in">atan2</span>(a.y, a.x));</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 角度转换成向量</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">angle2vector</span><span class="params">(<span class="keyword">float</span> angle, mathfu::Vector&lt;<span class="keyword">float</span>, <span class="number">2</span>&gt;&amp; a)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">auto</span> radian = <span class="built_in">angle2radian</span>(angle);</span><br><span class="line">    a.y = std::<span class="built_in">sin</span>(radian);</span><br><span class="line">    a.x = std::<span class="built_in">cos</span>(radian);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 按照角度，长度，转换一个位置</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">movepos</span><span class="params">(<span class="keyword">float</span> angle,mathfu::Vector&lt;<span class="keyword">float</span>,<span class="number">2</span>&gt;&amp; rawPos, <span class="keyword">float</span> len, mathfu::Vector&lt;<span class="keyword">float</span>, <span class="number">2</span>&gt;&amp; out)</span> </span>&#123;</span><br><span class="line">    mathfu::Vector&lt;<span class="keyword">float</span>, <span class="number">2</span>&gt; dir;</span><br><span class="line">    <span class="built_in">angle2vector</span>(angle, dir);</span><br><span class="line">    dir.x *= len;</span><br><span class="line">    dir.y *= len;</span><br><span class="line">    out = rawPos + dir;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 输出一个向量</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">outputvector</span><span class="params">(<span class="keyword">const</span> <span class="keyword">char</span>* tag, mathfu::Vector&lt;<span class="keyword">float</span>, <span class="number">2</span>&gt;&amp; a)</span> </span>&#123;</span><br><span class="line">    std::cout &lt;&lt; tag &lt;&lt; <span class="string">&quot; &quot;</span>&lt;&lt; a.x &lt;&lt; <span class="string">&quot;,&quot;</span> &lt;&lt; a.y &lt;&lt; <span class="string">&quot;\n&quot;</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h2 id="实例"><a href="#实例" class="headerlink" title="实例"></a>实例</h2><h3 id="1-计算围绕role的怪物"><a href="#1-计算围绕role的怪物" class="headerlink" title="1.计算围绕role的怪物"></a>1.计算围绕role的怪物</h3><blockquote>
<p>先检查是否和其他怪物重合<br>按照±小角度开始偏移尝试是否能站</p>
</blockquote>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line">#<span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&quot;mathfu/vector.h&quot;</span></span></span><br><span class="line">#<span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&quot;mathfu/constants.h&quot;</span></span></span><br><span class="line">#<span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;iostream&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">float</span> <span class="title">radian2angle</span><span class="params">(<span class="keyword">float</span> radian)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> radian * (<span class="number">180.0f</span> / mathfu::kPi);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">float</span> <span class="title">angle2radian</span><span class="params">(<span class="keyword">float</span> angle)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> angle * (mathfu::kPi / <span class="number">180.0f</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">float</span> <span class="title">vector2angle</span><span class="params">(mathfu::Vector&lt;<span class="keyword">float</span>, <span class="number">2</span>&gt; a)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> std::<span class="built_in">atan2</span>(a.y, a.x)*(<span class="number">180.0f</span> / mathfu::kPi);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">angle2vector</span><span class="params">(<span class="keyword">float</span> angle, mathfu::Vector&lt;<span class="keyword">float</span>, <span class="number">2</span>&gt;&amp; a)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">auto</span> radian = <span class="built_in">angle2radian</span>(angle);</span><br><span class="line">    a.y = std::<span class="built_in">sin</span>(radian);</span><br><span class="line">    a.x = std::<span class="built_in">cos</span>(radian);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">outputvector</span><span class="params">(<span class="keyword">const</span> <span class="keyword">char</span>* tag, mathfu::Vector&lt;<span class="keyword">float</span>, <span class="number">2</span>&gt;&amp; a)</span> </span>&#123;</span><br><span class="line">    std::cout &lt;&lt; tag &lt;&lt; <span class="string">&quot;=(&quot;</span> &lt;&lt; a.x &lt;&lt; <span class="string">&quot;,&quot;</span> &lt;&lt; a.y &lt;&lt; <span class="string">&quot;)\n&quot;</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// rawBattleCircleFix posSelf: linmath.Vector3&#123;X:11424.3, Y:-311.48605, Z:17336.395&#125;, </span></span><br><span class="line"><span class="comment">// posEnemy: linmath.Vector3&#123;X:11330.254, Y:-311.48605, Z:17465.838&#125;,</span></span><br><span class="line"><span class="comment">// newPos: linmath.Vector3&#123;X:11245.467, Y:-311.48605, Z:17601.525&#125;,</span></span><br><span class="line"><span class="comment">// angle: -32, e2sLen: 160.00067</span></span><br><span class="line"><span class="comment">// 测试怪物按照弧形排布在玩家周围</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">test_monster_battle_cricle</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">float</span> dst = <span class="number">160.0f</span>; <span class="comment">// 怪物距离</span></span><br><span class="line">    <span class="keyword">float</span> bodyRadius = <span class="number">80.0f</span>;<span class="comment">// 怪物的宽度</span></span><br><span class="line"></span><br><span class="line">    <span class="function">mathfu::Vector&lt;<span class="keyword">float</span>, 2&gt; <span class="title">monsterPos</span><span class="params">(<span class="number">11424.3f</span>, <span class="number">17336.395f</span>)</span></span>;</span><br><span class="line">    <span class="function">mathfu::Vector&lt;<span class="keyword">float</span>, 2&gt; <span class="title">rolePos</span><span class="params">(<span class="number">11330.254f</span>, <span class="number">17465.838f</span>)</span></span>;</span><br><span class="line">    <span class="keyword">auto</span> dir = monsterPos - rolePos;</span><br><span class="line">    <span class="keyword">auto</span> angle = <span class="built_in">vector2angle</span>(dir) + <span class="number">20.0f</span>;</span><br><span class="line"></span><br><span class="line">    mathfu::Vector&lt;<span class="keyword">float</span>, <span class="number">2</span>&gt; finalDir;</span><br><span class="line">    <span class="built_in">angle2vector</span>(angle, finalDir);</span><br><span class="line"></span><br><span class="line">    finalDir.x *= dst;</span><br><span class="line">    finalDir.y *= dst;</span><br><span class="line"></span><br><span class="line">    mathfu::Vector&lt;<span class="keyword">float</span>, <span class="number">2</span>&gt; newPos = rolePos + finalDir;</span><br><span class="line">    </span><br><span class="line">    <span class="built_in">outputvector</span>(<span class="string">&quot;monsterPos&quot;</span>, monsterPos);</span><br><span class="line">    <span class="built_in">outputvector</span>(<span class="string">&quot;rolePos&quot;</span>, rolePos);</span><br><span class="line">    <span class="built_in">outputvector</span>(<span class="string">&quot;newPos&quot;</span>,newPos);</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>cmake定义文件</p>
<figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">cmake_minimum_required</span> (VERSION <span class="number">3.2</span>)</span><br><span class="line"><span class="keyword">project</span>(math_base)</span><br><span class="line"></span><br><span class="line"><span class="keyword">IF</span> (CMAKE_SYSTEM_NAME <span class="keyword">MATCHES</span> <span class="string">&quot;Windows&quot;</span>)</span><br><span class="line">    <span class="keyword">add_definitions</span>(-DWIN32)</span><br><span class="line">    <span class="keyword">add_definitions</span>(-DWIN32_LEAN_AND_MEAN)</span><br><span class="line">    <span class="keyword">add_definitions</span>(-D_WINSOCK_DEPRECATED_NO_WARNINGS)</span><br><span class="line">    <span class="keyword">add_definitions</span>(-D_CRT_SECURE_NO_WARNINGS)</span><br><span class="line">    <span class="keyword">add_definitions</span>(-D_USE_MATH_DEFINES)</span><br><span class="line"><span class="keyword">ENDIF</span> (CMAKE_SYSTEM_NAME <span class="keyword">MATCHES</span> <span class="string">&quot;Windows&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">include_directories</span>( $ENV&#123;MATHFU_PATH&#125;/<span class="keyword">include</span> )</span><br><span class="line"></span><br><span class="line"><span class="keyword">file</span>(GLOB_RECURSE all_SRC <span class="string">&quot;src/*.cpp&quot;</span> </span><br><span class="line">    <span class="string">&quot;src/*.hpp&quot;</span> <span class="string">&quot;src/*.h&quot;</span> </span><br><span class="line">    <span class="string">&quot;src/*.cc&quot;</span> )</span><br><span class="line"></span><br><span class="line"><span class="keyword">add_executable</span>(test_math <span class="variable">$&#123;all_SRC&#125;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">target_link_libraries</span>(test_math)</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>计算的位置，在坐标系上的位置</p>
<p><a target="_blank" rel="noopener" href="https://imgchr.com/i/rOkIH0"><img src="https://s3.ax1x.com/2020/12/30/rOkIH0.png" alt="rOkIH0.png"></a></p>
<h3 id="2-计算园外切线"><a href="#2-计算园外切线" class="headerlink" title="2.计算园外切线"></a>2.计算园外切线</h3><p>利用三角函数来计算点对于圆的切线；</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">test_fun_fix_circle</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="comment">// 圆半径</span></span><br><span class="line">    <span class="keyword">float</span> radius = <span class="number">8.0f</span>;</span><br><span class="line">    <span class="comment">// 圆心位置</span></span><br><span class="line">    <span class="function">mathfu::Vector&lt;<span class="keyword">float</span>, 2&gt; <span class="title">circlePos</span><span class="params">(<span class="number">0</span>, <span class="number">0</span>)</span></span>;</span><br><span class="line">    <span class="comment">// 园外一点</span></span><br><span class="line">    <span class="function">mathfu::Vector&lt;<span class="keyword">float</span>, 2&gt; <span class="title">checkPos</span><span class="params">(<span class="number">10</span>, <span class="number">12</span>)</span></span>;</span><br><span class="line">    <span class="comment">// 园外点指向圆心向量</span></span><br><span class="line">    mathfu::Vector&lt;<span class="keyword">float</span>, <span class="number">2</span>&gt; l = circlePos - checkPos;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 计算距离</span></span><br><span class="line">    <span class="keyword">auto</span> len = l.<span class="built_in">Length</span>();</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 计算出园外点指向圆心向量角度</span></span><br><span class="line">    <span class="keyword">float</span> cos = radius / len;</span><br><span class="line">    <span class="keyword">float</span> radian = std::<span class="built_in">acos</span>(cos);</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 直角三角形，计算另一角度</span></span><br><span class="line">    <span class="keyword">float</span> offsetangle = <span class="number">90</span> - <span class="built_in">radian2angle</span>(radian);</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 将园外点指向圆心向量归一化，将向量转换成角度</span></span><br><span class="line">    <span class="keyword">auto</span> dir = l.<span class="built_in">Normalized</span>();</span><br><span class="line">    <span class="keyword">auto</span> oldAngle = <span class="built_in">vector2angle</span>(l);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 将 园外点指向圆心向量角度 + 通过直角三角形方式计算出来的夹角</span></span><br><span class="line">    <span class="comment">// 这个夹角就切线方向</span></span><br><span class="line">    <span class="keyword">auto</span> finalAngle = oldAngle + offsetangle;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 将角度换算成为向量</span></span><br><span class="line">    mathfu::Vector&lt;<span class="keyword">float</span>, <span class="number">2</span>&gt; finalDir;</span><br><span class="line">    <span class="built_in">angle2vector</span>(finalAngle, finalDir);</span><br><span class="line"></span><br><span class="line">    <span class="built_in">outputvector</span>(<span class="string">&quot;finalDir&quot;</span>, finalDir);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 计算出切线点离 园外点 的距离，将向量长度设置成这个距离</span></span><br><span class="line">    <span class="keyword">auto</span> al = std::<span class="built_in">sqrt</span>(len * len - radius * radius);</span><br><span class="line">    finalDir.x = finalDir.x * al;</span><br><span class="line">    finalDir.y = finalDir.y * al;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 使用 园外点 + 偏移向量就能得到切线过圆边的点</span></span><br><span class="line">    <span class="keyword">auto</span> finalPos = checkPos + finalDir;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">outputvector</span>(<span class="string">&quot;finalPos&quot;</span>, finalPos);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>效果：</p>
<p><a target="_blank" rel="noopener" href="https://imgchr.com/i/si1XZQ"><img src="https://s3.ax1x.com/2021/01/04/si1XZQ.png" alt="si1XZQ.png"></a></p>
<h3 id="3-计算某个点是否为三角形内"><a href="#3-计算某个点是否为三角形内" class="headerlink" title="3.计算某个点是否为三角形内"></a>3.计算某个点是否为三角形内</h3><p>原理在 b站 <a target="_blank" rel="noopener" href="https://www.bilibili.com/video/BV1X7411F744?p=2">GAMES101-现代计算机图形学入门-闫令琪</a> 38分钟处讲解了。</p>
<p>叉积是用于控制左右。如果获取的值域是正数左边，负数为右边。</p>
<p>利用的是，三角形三点按照顺时针的向量，以及p点的向量的叉乘永远是相同的象限的。</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">float</span> <span class="title">cross_vector2</span><span class="params">(mathfu::Vector&lt;<span class="keyword">float</span>, <span class="number">2</span>&gt;&amp; v1, mathfu::Vector&lt;<span class="keyword">float</span>, <span class="number">2</span>&gt;&amp; v2)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="keyword">return</span> v1.x * v2.y - v2.x * v1.y;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">test_triangle_inner</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="function">mathfu::Vector&lt;<span class="keyword">float</span>, 2&gt; <span class="title">A</span><span class="params">(<span class="number">8.66992</span>, <span class="number">6.79278</span>)</span></span>;</span><br><span class="line">	<span class="function">mathfu::Vector&lt;<span class="keyword">float</span>, 2&gt; <span class="title">B</span><span class="params">(<span class="number">4.96974</span>, <span class="number">2.1609</span>)</span></span>;</span><br><span class="line">	<span class="function">mathfu::Vector&lt;<span class="keyword">float</span>, 2&gt; <span class="title">C</span><span class="params">(<span class="number">12.31686</span>, <span class="number">1.78822</span>)</span></span>;</span><br><span class="line">	<span class="function">mathfu::Vector&lt;<span class="keyword">float</span>, 2&gt; <span class="title">P</span><span class="params">(<span class="number">8.98936</span>, <span class="number">4.07754</span>)</span></span>;</span><br><span class="line"></span><br><span class="line">	<span class="function">mathfu::Vector&lt;<span class="keyword">float</span>, 2&gt; <span class="title">P2</span><span class="params">(<span class="number">11</span>, <span class="number">5</span>)</span></span>;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">auto</span> u = B - A;</span><br><span class="line">	<span class="keyword">auto</span> v = C - B;</span><br><span class="line">	<span class="keyword">auto</span> w = A - C;</span><br><span class="line"></span><br><span class="line">	std::cout &lt;&lt; <span class="string">&quot;start check P\n&quot;</span>;</span><br><span class="line">	<span class="keyword">auto</span> t = P - A;</span><br><span class="line">	std::cout &lt;&lt; <span class="built_in">cross_vector2</span>(t, u) &lt;&lt; <span class="string">&quot;\n&quot;</span>;</span><br><span class="line">	t = P - B;</span><br><span class="line">	std::cout &lt;&lt; <span class="built_in">cross_vector2</span>(t, v) &lt;&lt; <span class="string">&quot;\n&quot;</span>;</span><br><span class="line">	t = P - C;</span><br><span class="line">	std::cout &lt;&lt; <span class="built_in">cross_vector2</span>(t, w) &lt;&lt; <span class="string">&quot;\n&quot;</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">	std::cout &lt;&lt; <span class="string">&quot;start check P2\n&quot;</span>;</span><br><span class="line">	t = P2 - A;</span><br><span class="line">	std::cout &lt;&lt; <span class="built_in">cross_vector2</span>(t, u) &lt;&lt; <span class="string">&quot;\n&quot;</span>;</span><br><span class="line">	t = P2 - B;</span><br><span class="line">	std::cout &lt;&lt; <span class="built_in">cross_vector2</span>(t, v) &lt;&lt; <span class="string">&quot;\n&quot;</span>;</span><br><span class="line">	t = P2 - C;</span><br><span class="line">	std::cout &lt;&lt; <span class="built_in">cross_vector2</span>(t, w) &lt;&lt; <span class="string">&quot;\n&quot;</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//output:</span></span><br><span class="line"><span class="comment">//start check P</span></span><br><span class="line"><span class="comment">//11.3947</span></span><br><span class="line"><span class="comment">//28.8183</span></span><br><span class="line"><span class="comment">//23.5922</span></span><br><span class="line"><span class="comment">//start check P2</span></span><br><span class="line"><span class="comment">//- 0.317775</span></span><br><span class="line"><span class="comment">//43.247</span></span><br><span class="line"><span class="comment">//20.8761</span></span><br><span class="line"><span class="comment">// 如果旋转方向相同，这些向量的sin值的符号都是一致的。</span></span><br><span class="line"><span class="comment">//</span></span><br></pre></td></tr></table></figure>

<p><a target="_blank" rel="noopener" href="https://imgchr.com/i/snVFIJ"><img src="https://s3.ax1x.com/2021/01/08/snVFIJ.png" alt="snVFIJ.png"></a></p>
<h3 id="4-计算矩形内的一点"><a href="#4-计算矩形内的一点" class="headerlink" title="4.计算矩形内的一点"></a>4.计算矩形内的一点</h3><p>原理和三角形检查一样。</p>
<p>先将一个矩形做偏移，旋转：</p>
<p><a target="_blank" rel="noopener" href="https://imgchr.com/i/s2djk4"><img src="https://s3.ax1x.com/2021/01/19/s2djk4.png" alt="s2djk4.png"></a></p>
<p>取两个点开始计算：</p>
<p><a target="_blank" rel="noopener" href="https://imgchr.com/i/s2wm9A"><img src="https://s3.ax1x.com/2021/01/19/s2wm9A.png" alt="s2wm9A.png"></a></p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">test_rect_inner</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="function">mathfu::Vector&lt;<span class="keyword">float</span>, 2&gt; <span class="title">r1</span><span class="params">(<span class="number">-4</span>, <span class="number">-5</span>)</span></span>;</span><br><span class="line">    <span class="function">mathfu::Vector&lt;<span class="keyword">float</span>, 2&gt; <span class="title">r2</span><span class="params">(<span class="number">-1.401923789</span>, <span class="number">-3.5</span>)</span></span>;</span><br><span class="line">    <span class="function">mathfu::Vector&lt;<span class="keyword">float</span>, 2&gt; <span class="title">r3</span><span class="params">(<span class="number">-4.901923789</span>, <span class="number">2.562177826</span>)</span></span>;</span><br><span class="line">    <span class="function">mathfu::Vector&lt;<span class="keyword">float</span>, 2&gt; <span class="title">r4</span><span class="params">(<span class="number">-7.5</span>, <span class="number">1.062177826</span>)</span></span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="function">mathfu::Vector&lt;<span class="keyword">float</span>, 2&gt; <span class="title">i</span><span class="params">(<span class="number">-4.88</span>, <span class="number">-1.49</span>)</span></span>;</span><br><span class="line">    <span class="function">mathfu::Vector&lt;<span class="keyword">float</span>, 2&gt; <span class="title">j</span><span class="params">(<span class="number">-8.26</span>, <span class="number">-3.77</span>)</span></span>;</span><br><span class="line"></span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;计算i点\n&quot;</span>;</span><br><span class="line">    <span class="keyword">auto</span> t1 = r2 - r1;</span><br><span class="line">    <span class="keyword">auto</span> t2 = i - r1;</span><br><span class="line">    std::cout &lt;&lt; mathfu::Vector&lt;<span class="keyword">float</span>, <span class="number">2</span>&gt;::<span class="built_in">DotProduct</span>(t1,t2) &lt;&lt; <span class="string">&quot;\n&quot;</span>;</span><br><span class="line">    t1 = r3 - r2;</span><br><span class="line">    t2 = i - r2;</span><br><span class="line">    std::cout &lt;&lt; mathfu::Vector&lt;<span class="keyword">float</span>, <span class="number">2</span>&gt;::<span class="built_in">DotProduct</span>(t1, t2) &lt;&lt; <span class="string">&quot;\n&quot;</span>;</span><br><span class="line">    t1 = r4 - r3;</span><br><span class="line">    t2 = i - r3;</span><br><span class="line">    std::cout &lt;&lt; mathfu::Vector&lt;<span class="keyword">float</span>, <span class="number">2</span>&gt;::<span class="built_in">DotProduct</span>(t1, t2) &lt;&lt; <span class="string">&quot;\n&quot;</span>;</span><br><span class="line">    t1 = r1 - r4;</span><br><span class="line">    t2 = i - r4;</span><br><span class="line">    std::cout &lt;&lt; mathfu::Vector&lt;<span class="keyword">float</span>, <span class="number">2</span>&gt;::<span class="built_in">DotProduct</span>(t1, t2) &lt;&lt; <span class="string">&quot;\n&quot;</span>;</span><br><span class="line"></span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;计算j点\n&quot;</span>;</span><br><span class="line"></span><br><span class="line">    t1 = r2 - r1;</span><br><span class="line">    t2 = j - r1;</span><br><span class="line">    std::cout &lt;&lt; mathfu::Vector&lt;<span class="keyword">float</span>, <span class="number">2</span>&gt;::<span class="built_in">DotProduct</span>(t1, t2) &lt;&lt; <span class="string">&quot;\n&quot;</span>;</span><br><span class="line">    t1 = r3 - r2;</span><br><span class="line">    t2 = j - r2;</span><br><span class="line">    std::cout &lt;&lt; mathfu::Vector&lt;<span class="keyword">float</span>, <span class="number">2</span>&gt;::<span class="built_in">DotProduct</span>(t1, t2) &lt;&lt; <span class="string">&quot;\n&quot;</span>;</span><br><span class="line">    t1 = r4 - r3;</span><br><span class="line">    t2 = j - r3;</span><br><span class="line">    std::cout &lt;&lt; mathfu::Vector&lt;<span class="keyword">float</span>, <span class="number">2</span>&gt;::<span class="built_in">DotProduct</span>(t1, t2) &lt;&lt; <span class="string">&quot;\n&quot;</span>;</span><br><span class="line">    t1 = r1 - r4;</span><br><span class="line">    t2 = j - r4;</span><br><span class="line">    std::cout &lt;&lt; mathfu::Vector&lt;<span class="keyword">float</span>, <span class="number">2</span>&gt;::<span class="built_in">DotProduct</span>(t1, t2) &lt;&lt; <span class="string">&quot;\n&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="5-计算两个角度相差"><a href="#5-计算两个角度相差" class="headerlink" title="5.计算两个角度相差"></a>5.计算两个角度相差</h3><p>这段代码是复制unreal engine4里面的。</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">template</span>&lt; class T &gt;</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">inline</span> T <span class="title">Sign</span><span class="params">(<span class="keyword">const</span> T A)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> (A &gt; (T)<span class="number">0</span>) ? (T)<span class="number">1</span> : ((A &lt; (T)<span class="number">0</span>) ? (T)<span class="number">-1</span> : (T)<span class="number">0</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">WindRelativeAnglesDegrees</span><span class="params">(<span class="keyword">float</span> InAngle0, <span class="keyword">float</span>&amp; InOutAngle1)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">const</span> <span class="keyword">float</span> Diff = InAngle0 - InOutAngle1;</span><br><span class="line">    <span class="keyword">const</span> <span class="keyword">float</span> AbsDiff = std::<span class="built_in">abs</span>(Diff);</span><br><span class="line">    <span class="keyword">if</span> (AbsDiff &gt; <span class="number">180.0f</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        InOutAngle1 += <span class="number">360.0f</span> * <span class="built_in">Sign</span>(Diff) * std::<span class="built_in">floor</span>((AbsDiff / <span class="number">360.0f</span>) + <span class="number">0.5f</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">test_windRelativeAngle</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">float</span> a0 = <span class="number">10</span>;</span><br><span class="line">    <span class="keyword">float</span> a1 = <span class="number">-10</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="built_in">WindRelativeAnglesDegrees</span>(a0, a1);</span><br><span class="line">    std::cout &lt;&lt; a0 - a1 &lt;&lt; <span class="string">&quot;\n&quot;</span>;</span><br><span class="line"></span><br><span class="line">    a0 = <span class="number">10</span>;</span><br><span class="line">    a1 = <span class="number">350</span>;</span><br><span class="line">    <span class="built_in">WindRelativeAnglesDegrees</span>(a0, a1);</span><br><span class="line">    std::cout &lt;&lt; a0 - a1 &lt;&lt; <span class="string">&quot;\n&quot;</span>;</span><br><span class="line"></span><br><span class="line">    a0 = <span class="number">370</span>;</span><br><span class="line">    a1 = <span class="number">20</span>;</span><br><span class="line">    <span class="built_in">WindRelativeAnglesDegrees</span>(a0, a1);</span><br><span class="line">    std::cout &lt;&lt; a0 - a1 &lt;&lt; <span class="string">&quot;\n&quot;</span>;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>大意就是将a0,a1两个角度（无论角度是不是±180°区间）计算了之后，再次做减法，计算出角度为夹角度数，且夹角会保持在±180°之内。</p>
<h3 id="6-角度格式化"><a href="#6-角度格式化" class="headerlink" title="6.角度格式化"></a>6.角度格式化</h3><p>// Utility to ensure angle is between +/- 180 degrees by unwinding.</p>
<figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 将度数限制在±180°</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">UnwindDegrees</span><span class="params">(A <span class="keyword">float64</span>)</span> <span class="params">(R <span class="keyword">float64</span>)</span></span> &#123;</span><br><span class="line">    <span class="keyword">for</span> A &gt; <span class="number">180.0</span> &#123;</span><br><span class="line">        A -= <span class="number">360.0</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">for</span> A &lt; <span class="number">-180.0</span> &#123;</span><br><span class="line">        A += <span class="number">360.0</span></span><br><span class="line">    &#125;</span><br><span class="line">    R = A</span><br><span class="line">    <span class="keyword">return</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="7-计算线段与圆相交"><a href="#7-计算线段与圆相交" class="headerlink" title="7. 计算线段与圆相交"></a>7. 计算线段与圆相交</h3><p><a target="_blank" rel="noopener" href="https://www.cnblogs.com/hont/p/8991751.html">参考文献</a></p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;mathfu/vector.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> Vector2 = mathfu::Vector&lt;<span class="keyword">float</span>, <span class="number">2</span>&gt;;</span><br><span class="line"></span><br><span class="line">Vector2 zero = <span class="built_in">Vector2</span>(<span class="number">0.0f</span>,<span class="number">0.0f</span>);</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">BetweenLineAndCircle</span><span class="params">(</span></span></span><br><span class="line"><span class="params"><span class="function">	Vector2 circleCenter, <span class="keyword">float</span> circleRadius,</span></span></span><br><span class="line"><span class="params"><span class="function">	Vector2 point1, Vector2 point2,</span></span></span><br><span class="line"><span class="params"><span class="function">	Vector2 &amp;intersection1, Vector2 &amp;intersection2)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="keyword">float</span> t;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">auto</span> dx = point2.x - point1.x;</span><br><span class="line">	<span class="keyword">auto</span> dy = point2.y - point1.y;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">auto</span> a = dx * dx + dy * dy;</span><br><span class="line">	<span class="keyword">auto</span> b = <span class="number">2</span> * (dx * (point1.x - circleCenter.x) + dy * (point1.y - circleCenter.y));</span><br><span class="line">	<span class="keyword">auto</span> c = (point1.x - circleCenter.x) * (point1.x - circleCenter.x) + (point1.y - circleCenter.y) * (point1.y - circleCenter.y) - circleRadius * circleRadius;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">auto</span> determinate = b * b - <span class="number">4</span> * a * c;</span><br><span class="line">	<span class="keyword">if</span> ((a &lt;= <span class="number">0.0000001</span>) || (determinate &lt; <span class="number">-0.0000001</span>))</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="comment">// No real solutions.</span></span><br><span class="line">		intersection1 = zero;</span><br><span class="line">		intersection2 = zero;</span><br><span class="line">		<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">if</span> (determinate &lt; <span class="number">0.0000001</span> &amp;&amp; determinate &gt; <span class="number">-0.0000001</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="comment">// One solution.</span></span><br><span class="line">		t = -b / (<span class="number">2</span> * a);</span><br><span class="line">		intersection1 = <span class="built_in">Vector2</span>(point1.x + t * dx, point1.y + t * dy);</span><br><span class="line">		intersection2 = zero;</span><br><span class="line">		<span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">// Two solutions.</span></span><br><span class="line">	t = (<span class="keyword">float</span>)((-b + std::<span class="built_in">sqrt</span>(determinate)) / (<span class="number">2</span> * a));</span><br><span class="line">	intersection1 = <span class="built_in">Vector2</span>(point1.x + t * dx, point1.y + t * dy);</span><br><span class="line">	t = (<span class="keyword">float</span>)((-b - std::<span class="built_in">sqrt</span>(determinate)) / (<span class="number">2</span> * a));</span><br><span class="line">	intersection2 = <span class="built_in">Vector2</span>(point1.x + t * dx, point1.y + t * dy);</span><br><span class="line"></span><br><span class="line">	<span class="keyword">return</span> <span class="number">2</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argn, <span class="keyword">char</span>* argc[])</span> </span>&#123;</span><br><span class="line">	<span class="function">Vector2 <span class="title">circleCenter</span><span class="params">(<span class="number">-2.84f</span>,<span class="number">2.82f</span>)</span></span>;</span><br><span class="line">	<span class="keyword">float</span> circleRadius = <span class="number">3.5f</span>;</span><br><span class="line">	<span class="function">Vector2 <span class="title">point1</span><span class="params">(<span class="number">-5.48f</span>,<span class="number">5.12f</span>)</span></span>;</span><br><span class="line">	<span class="function">Vector2 <span class="title">point2</span><span class="params">(<span class="number">-0.55f</span>,<span class="number">5.47</span>)</span></span>;</span><br><span class="line">	Vector2 intersection1;</span><br><span class="line">	Vector2 intersection2;</span><br><span class="line">	</span><br><span class="line">	<span class="keyword">int</span> pointCount = <span class="built_in">BetweenLineAndCircle</span>(circleCenter, circleRadius, point1, point2, intersection1, intersection2);</span><br><span class="line"></span><br><span class="line">	std::cout &lt;&lt; <span class="string">&quot;pointCount: &quot;</span> &lt;&lt; pointCount;	</span><br><span class="line"></span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h2 id="4-矩阵"><a href="#4-矩阵" class="headerlink" title="4.矩阵"></a>4.矩阵</h2><h3 id="1-概念"><a href="#1-概念" class="headerlink" title="1.概念"></a>1.概念</h3><p>$$<br>  \left|\begin{matrix}<br>   1 &amp; 2 &amp; 3 \<br>   4 &amp; 5 &amp; 6 \<br>   7 &amp; 8 &amp; 9<br>  \end{matrix}\right| \tag{A}<br>$$</p>
<p>矩阵是按照行列方式排列的数字。是线性代数里面中重要的数学概念。</p>
<p>描述矩阵一般都是说</p>
<p>$$r \times c$$</p>
<p>的矩阵。r是rows行（横着的条目算1个），c是column（竖着的条目算1个）</p>
<p><strong>方阵</strong>就是行和列数目都是相同的。在3d运算中经常使用这种方阵</p>
<p><strong>单位矩阵</strong>，对角线都是1，其余都是0。</p>
<p>$$<br>  \left|\begin{matrix}<br>   1 &amp; 0 &amp; 0 \<br>   0 &amp; 1 &amp; 0 \<br>   0 &amp; 0 &amp; 1<br>  \end{matrix}\right| \tag{M}<br>$$</p>
<p>书写的时候，矩阵都是写成大写。M，A，R。手写的时候，矩阵的括号其实要写成圆括号()，印刷体中都是[]表示。</p>
<p>向量转换成矩阵可以成为 行矩阵、列矩阵。</p>
<h3 id="2-矩阵运算"><a href="#2-矩阵运算" class="headerlink" title="2.矩阵运算"></a>2.矩阵运算</h3><ul>
<li>单位矩阵</li>
</ul>
<p>主对角线数字都为1，其他位置都为0。</p>
<h4 id="1-转置"><a href="#1-转置" class="headerlink" title="1.转置"></a>1.转置</h4><p>$$<br>\left|<br>  \begin{matrix}<br>   1 \<br>   2 \<br>   3<br>  \end{matrix}\right|\tag{M}<br>$$</p>
<p>$$<br>\left|<br>  \begin{matrix}<br>   1 &amp; 2 &amp; 3\<br>  \end{matrix} \tag{A}\right|<br>$$</p>
<p>记作：</p>
<p>$$M^t=A$$</p>
<h4 id="2-矩阵与标量乘"><a href="#2-矩阵与标量乘" class="headerlink" title="2.矩阵与标量乘"></a>2.矩阵与标量乘</h4><p>$$<br>M<em>k= k <em>\left|<br>  \begin{matrix}<br>   m11 &amp; m12 &amp; m13\<br>   m21 &amp; m22 &amp; m23\<br>   m31 &amp; m32 &amp; m33\<br>  \end{matrix} \right| = k \left|<br>  \begin{matrix}<br>   k</em>m11 &amp; k</em>m12 &amp; k<em>m13\<br>   k</em>m21 &amp; k<em>m22 &amp; k</em>m23\<br>   k<em>m31 &amp; k</em>m32 &amp; k*m33\<br>  \end{matrix} \right|<br>$$</p>
<h4 id="3-矩阵乘法"><a href="#3-矩阵乘法" class="headerlink" title="3.矩阵乘法"></a>3.矩阵乘法</h4><p>公式定义：</p>
<p>$$(AB)<em>{ij}=\sum</em>{k=1}^p a_{i1}b_{1j}+a_{i2}b_{2j}+…+a_{ip}b_{pj}$$</p>
<p>公式分解：</p>
<p>$$<br>A*B= \left|<br>  \begin{matrix}<br>   a11 &amp; a12 &amp; a13\<br>   a21 &amp; a22 &amp; a23\<br>  \end{matrix} \right| * \left|<br>  \begin{matrix}<br>   b11 &amp; b12 \<br>   b21 &amp; b22 \<br>   b31 &amp; b32 \<br>  \end{matrix} \right|=\left|<br>  \begin{matrix}<br>   a11b11+a12b21+a13b31 &amp; a11b21+ a12b22+a13b23\<br>   a21b11+a22+b21+a23b31 &amp; a21b12+a22b22+a23b32\<br>  \end{matrix} \right|<br>$$</p>
<p>$$A*B=C$$</p>
<p>1、当矩阵A的列数（column）等于矩阵B的行数（row）时，A与B可以相乘。</p>
<p>2、矩阵C的行数等于矩阵A的行数，C的列数等于B的列数。</p>
<p>3、乘积C的第m行第n列的元素等于矩阵A的第m行的元素与矩阵B的第n列对应元素乘积之和。</p>
<p>在线性代数课程中，宋老师的7字口诀：</p>
<p>宋老师七字口诀：</p>
<p>$$A_{3 \times 4} B_{4 \times 5} $$</p>
<p>中间相等，取两头。</p>
<p>其实就是罗列矩阵的下标数字：</p>
<p>3,4,4,5</p>
<p>中间数字： 4,4相等，就能乘；</p>
<p>取两头： 3,5 这就是结果的矩阵的形状。</p>
<p><a target="_blank" rel="noopener" href="https://jingyan.baidu.com/article/2d5afd69348d7685a2e28eb8.html">wps矩阵计算</a></p>
<p>使用矩阵来做位移，旋转，缩放操作：</p>
<p><a target="_blank" rel="noopener" href="https://imgchr.com/i/sBTkV0"><img src="https://s3.ax1x.com/2021/01/16/sBTkV0.png" alt="sBTkV0.png"></a></p>
<p>坐标系上的位置：</p>
<p><a target="_blank" rel="noopener" href="https://imgchr.com/i/sBoz8g"><img src="https://s3.ax1x.com/2021/01/16/sBoz8g.png" alt="sBoz8g.png"></a></p>
<h4 id="4-克罗内克积（Kronecker-Product）"><a href="#4-克罗内克积（Kronecker-Product）" class="headerlink" title="4.克罗内克积（Kronecker Product）"></a>4.克罗内克积（Kronecker Product）</h4><p>克罗内克积是两个任意大小的矩阵间的运算，符号记作 。克罗内克积也被称为直积或张量积.以德国数学家利奥波德·克罗内克命名。</p>
<p>$$<br>\left|<br>  \begin{matrix}<br>   a11 &amp; a12 \<br>   a21 &amp; a22 \<br>  \end{matrix} \right| \bigotimes<br>\left|<br>  \begin{matrix}<br>   b11 &amp; b12 \<br>   b12 &amp; b22 \<br>  \end{matrix} \right|<br>  = \left|<br>  \begin{matrix}<br>   a11b11 &amp; a11b12 &amp; a12b11 &amp; a12b12 \<br>   a11b21 &amp; a11b22 &amp; a12b21 &amp; a12b22 \<br>   a21b11 &amp; a11b12 &amp; a22b21 &amp; a22b22 \<br>   a21b21 &amp; a21b22 &amp; a22b21 &amp; a22b22 \<br>  \end{matrix} \right|<br>$$</p>
<h2 id="6-欧拉角"><a href="#6-欧拉角" class="headerlink" title="6.欧拉角"></a>6.欧拉角</h2><p>先使用左手坐标系。</p>
<p>摆上一个飞机，y轴指天，x轴右，z轴向前。</p>
<ol>
<li>飞机围绕着y轴旋转，叫做偏离航向（heading），偏航角（Yaw），航向角（Heading Angle）；</li>
<li>飞机围绕着x轴旋转，叫做俯仰（pitch）调整，俯仰角（Pitch），偏斜角（Angle of Declination）；</li>
<li>飞机围绕着z轴旋转，叫做滚转（bank）调整，翻滚角（Roll）；</li>
</ol>
<h3 id="4-万向节死锁"><a href="#4-万向节死锁" class="headerlink" title="4.万向节死锁"></a>4.万向节死锁</h3><p>在使用欧拉角来做旋转的时候，当我们将俯仰数值调整成±90°的时候。再去调整偏航、滚转的时候，保持一致。本来有3个维度上的旋转，最后只能从两个维度上调整。</p>
<p>欧拉角和后面说的四元数的插值计算也是存在一些差异的。</p>
<p><a target="_blank" rel="noopener" href="https://www.bilibili.com/video/av883112934/">欧拉角、四元数插值差异</a></p>
<p>插值的时候，四元数可以使用球形插值SLerp，在空间上转换的时候，会在球面上画弧线。欧拉角是按照轴来做的。</p>
<h3 id="2-欧拉恒等式"><a href="#2-欧拉恒等式" class="headerlink" title="2.欧拉恒等式"></a>2.欧拉恒等式</h3><p>我还没有理解到这个意义。</p>
<p>$$\cos\varphi+i\sin\varphi=e^{i\varphi}$$</p>
<p>当</p>
<p>$$\varphi=\pi$$</p>
<p>推导</p>
<p>$$e^{i\pi}+1=0$$</p>
<h2 id="5-四元数"><a href="#5-四元数" class="headerlink" title="5.四元数"></a>5.四元数</h2><h3 id="1-概述"><a href="#1-概述" class="headerlink" title="1.概述"></a>1.概述</h3><p>四元数是1843年发明的。爱尔兰数学家哈密顿(William Rowan Hamilton,1805-1865）。</p>
<p>四元数运算在电动力学与广义相对论中有广泛的应用。四元数可以用来取代张量表示。有时候采用带有复数元素之四元数会比较容易，导得结果不为除法代数之形式。然而亦可结合共轭运算以达到相同的运算结果。</p>
<p>从概念上来看，就是在数学里面定义对于-1开方最后获取的值。</p>
<p>$$i=\sqrt{-1}$$</p>
<p>复数是对实数集合的一种扩展。</p>
<p>在游戏开发应用里面，四元数用于做旋转计算。所以最好先将矩阵搞清楚。复数已经是一种数学工具了，在实际世界里面不能表示什么意义。</p>
<p>四元数不是专门给3D图形学设计的，但是能用在3D图形学里面：</p>
<ul>
<li>[3D相机控制]</li>
<li>压缩存储</li>
<li>平滑3D插值</li>
</ul>
<p><strong>复数</strong>定义</p>
<p>$$z=a+b*i$$</p>
<p>a是实部，b是虚部；</p>
<p><strong>复数</strong>与标量相乘、相除</p>
<p>$$k<em>Z_{1}=k</em>(a+bi)=k<em>a+(k</em>b)*i$$</p>
<p><strong>复数</strong>加减</p>
<p>$$Z_{1}=(a+b*i)$$</p>
<p>$$Z_{2}=(c+d*i)$$</p>
<p>$$Z_{1}+Z_{2}=(a+b<em>i)+(c+d</em>i)=((a+c)+(b+d)*i)$$</p>
<p>$$Z_{1}-Z_{2}=(a+bi)-(c+di)=(a-c)+(b-d)i$$</p>
<p><strong>复数</strong>加法恒等元</p>
<p>复数恒等元</p>
<p>$$(0+0*i)$$</p>
<p><strong>复数</strong>除法</p>
<p>$$Z_{1}/Z_{2}=\frac{(a+b<em>i)}{(c+d</em>i)}$$</p>
<p>推算的时候，需要分子和分母都乘上分母的共轭复数。</p>
<p><strong>共轭</strong>(Conjugate)</p>
<p>两个实部相等，虚部互为相反数的复数互为共轭复数(conjugate complex number)。（当虚部不等于0时也叫共轭虚数）复数z的共轭复数记作 （z上加一横，英文中可读作Conjugate z,z conjugate or z bar），有时也可表示为</p>
<p>$$Z^*=\overline{Z}$$</p>
<p>$$Z=(a+bi)$$</p>
<p>$$\overline{Z}=(a-bi)$$</p>
<p>计算负数的模</p>
<p>$$\left||p\right||=\sqrt{p\overline{p}}$$</p>
<p><del>中划线</del></p>
<p>$$\underline{\text{下划线}}$$</p>
<p>$$\overline{\text{上划线}}$$</p>
<h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul>
<li>[1] <a target="_blank" rel="noopener" href="https://blog.csdn.net/u013914471/article/details/82973812">markdown公式</a></li>
<li>[2] <a target="_blank" rel="noopener" href="https://jingyan.baidu.com/article/2c8c281d17d3f94109252a1c.html">windows10输入公式</a></li>
<li>[3] <a target="_blank" rel="noopener" href="https://baike.baidu.com/item/%E4%B8%89%E8%A7%92%E5%87%BD%E6%95%B0/1652457?fr=aladdin">三角函数</a></li>
<li>[4] <a target="_blank" rel="noopener" href="https://www.geogebra.org/graphing">图形计算器</a></li>
<li>[5] <a target="_blank" rel="noopener" href="https://www.zhihu.com/column/GGBmath">GeoGebra数学</a></li>
<li>[6] <a target="_blank" rel="noopener" href="https://www.geogebra.org/classic">GeoGebra-Classic</a></li>
<li>[7] <a target="_blank" rel="noopener" href="https://github.com/google/mathfu">Google-mathfun库</a></li>
<li>[8] <a target="_blank" rel="noopener" href="https://www.bilibili.com/video/BV1X7411F744?p=2">GAMES101-现代计算机图形学入门-闫令琪</a></li>
<li>[9] <a target="_blank" rel="noopener" href="https://www.runoob.com/numpy/numpy-tutorial.html">NumPy教程</a></li>
<li>[10] <a target="_blank" rel="noopener" href="https://pypi.org/project/euclid/">2d/3dPython库</a></li>
<li>[11] <a target="_blank" rel="noopener" href="https://blog.csdn.net/nuoyanli/article/details/96179976">markdown公式2</a></li>
<li>[12] <a target="_blank" rel="noopener" href="https://muzhan.blog.csdn.net/article/details/81385790?utm_medium=distribute.pc_relevant.none-task-blog-searchFromBaidu-3.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-searchFromBaidu-3.control">markdown公式3</a></li>
<li>[13] <a target="_blank" rel="noopener" href="https://www.bilibili.com/video/BV1xJ411M7Rz?p=10">B站矩阵</a></li>
<li>[14] <a target="_blank" rel="noopener" href="https://baike.baidu.com/item/%E6%9E%81%E5%9D%90%E6%A0%87%E7%B3%BB/2381612?fr=aladdin">极坐标</a></li>
<li>[15] <a target="_blank" rel="noopener" href="https://blog.csdn.net/u012909508/article/details/81910770?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.control">3d数学笔记</a></li>
<li>[16] <a target="_blank" rel="noopener" href="https://www.bilibili.com/video/BV1ns411J7Qs?from=search&seid=9841395523045088295">妈咪说-复数</a></li>
<li>[17] <a target="_blank" rel="noopener" href="https://download.geogebra.org/installers/6.0/GeoGebra-Windows-Installer-6-0-620-0.exe">GeoGebra-Classic-Win版本</a></li>
<li>[18] <a target="_blank" rel="noopener" href="https://baike.baidu.com/item/%E5%A4%8D%E6%95%B0%E8%BF%90%E7%AE%97%E6%B3%95%E5%88%99/2568041?fr=aladdin">复数运算规则</a></li>
<li>[19] <a target="_blank" rel="noopener" href="https://blog.csdn.net/wwlcsdn000/article/details/79421612">欧拉角和四元数的理解</a></li>
<li>[20] <a target="_blank" rel="noopener" href="https://blog.csdn.net/andrewfan/article/details/60981437">欧拉角和万向节死锁</a></li>
<li>[21] <a target="_blank" rel="noopener" href="https://www.bilibili.com/video/BV1Bt4y1v7R1?from=search&seid=14532893400995846237">万向节死锁实例</a></li>
<li>[22] <a target="_blank" rel="noopener" href="https://latex.91maths.com/">在线LaTex工具</a></li>
<li>[23] <a target="_blank" rel="noopener" href="https://www.bilibili.com/video/av58055882/">3D数学基础图形与游戏开发-视频</a></li>
</ul>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://example.com/2020/12/29/2020/2020-12-29-3d%E6%95%B0%E5%AD%A6/" data-id="ckrn3an7r002i20xw3sam9hj3" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/3D/" rel="tag">3D</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Math/" rel="tag">Math</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-2020/2020-12-24-cgo使用" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2020/12/24/2020/2020-12-24-cgo%E4%BD%BF%E7%94%A8/" class="article-date">
  <time datetime="2020-12-23T16:00:00.000Z" itemprop="datePublished">2020-12-24</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2020/12/24/2020/2020-12-24-cgo%E4%BD%BF%E7%94%A8/">cgo的使用</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <p>golang可以通过cgo直接来调用c/c++的函数代码。这里是参考《Go语言高级编程》书，做一些笔记。结构按照书的章节来。</p>
<ul>
<li><a href="#1%E5%BF%AB%E9%80%9F%E5%85%A5%E6%89%8B">1.快速入手</a></li>
<li><a href="#2cgo%E5%9F%BA%E7%A1%80">2.CGO基础</a><ul>
<li><a href="#21%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%8C%BA%E5%88%86">2.1.操作系统区分</a></li>
</ul>
</li>
<li><a href="#3%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2">3.类型转换</a></li>
<li><a href="#4%E5%87%BD%E6%95%B0%E8%B0%83%E7%94%A8">4.函数调用</a></li>
<li><a href="#6%E5%AE%9E%E4%BE%8B">6.实例</a></li>
<li><a href="#10%E7%BC%96%E8%AF%91%E9%93%BE%E6%8E%A5%E5%8F%82%E6%95%B0">10.编译/链接参数</a></li>
<li><a href="#%E5%8F%82%E8%80%83">参考</a></li>
</ul>
<h1 id="1-快速入手"><a href="#1-快速入手" class="headerlink" title="1.快速入手"></a>1.快速入手</h1><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// hello.go</span></span><br><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> <span class="string">&quot;C&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    <span class="built_in">println</span>(<span class="string">&quot;hello cgo&quot;</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h1 id="2-CGO基础"><a href="#2-CGO基础" class="headerlink" title="2.CGO基础"></a>2.CGO基础</h1><p>需要安装C/C++构建工具链，在macOS和Linux下是要安装GCC，在windows下是需要安装MinGW工具。同时需要保证环境变量CGO_ENABLED被设置为1，这表示CGO是被启用的状态。</p>
<p>Windows里面使用的MinGW工具</p>
<figure class="highlight bat"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">mingw64\mingw64\bin&gt;.\g++.exe --version</span><br><span class="line">g++.exe (x86_64-win32-seh-rev0, Built by MinGW-W64 project) <span class="number">8</span>.<span class="number">1</span>.<span class="number">0</span></span><br><span class="line">Copyright (C) <span class="number">2018</span> Free Software Foundation, Inc.</span><br><span class="line">This is free software; see the source <span class="keyword">for</span> copying conditions.  There is NO</span><br><span class="line">warranty; <span class="keyword">not</span> even <span class="keyword">for</span> MERCHANTABILITY or FITNESS <span class="keyword">FOR</span> A PARTICULAR PURPOSE.</span><br><span class="line"></span><br><span class="line">// 在 strawberryperl 也有一个版本。</span><br><span class="line">PS D:\work\trunk\doc&gt; gcc --version</span><br><span class="line">gcc.exe (x86_64-posix-seh, Built by strawberryperl.com project) <span class="number">8</span>.<span class="number">3</span>.<span class="number">0</span></span><br><span class="line">Copyright (C) <span class="number">2018</span> Free Software Foundation, Inc.</span><br><span class="line">This is free software; see the source <span class="keyword">for</span> copying conditions.  There is NO</span><br><span class="line">warranty; <span class="keyword">not</span> even <span class="keyword">for</span> MERCHANTABILITY or FITNESS <span class="keyword">FOR</span> A PARTICULAR PURPOSE.</span><br><span class="line"></span><br><span class="line">It includes perl binaries, compiler (gcc) + related tools, all the external libraries (crypto, math, graphics, xml…), all the bundled database clients and all you expect from Strawberry Perl.</span><br></pre></td></tr></table></figure>

<p><a href="#%E5%8F%82%E8%80%83">gcc编译器对标准支持情况</a> gcc 8.x 版本的编译器已经能编译大部分c++17标准的东西了。</p>
<h2 id="2-1-操作系统区分"><a href="#2-1-操作系统区分" class="headerlink" title="2.1.操作系统区分"></a>2.1.操作系统区分</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#cgo windows CFLAGS: -DCGO_OS_WINDOWS=1</span></span><br><span class="line"><span class="comment">#cgo darwin CFLAGS: -DCGO_OS_DARWIN=1</span></span><br><span class="line"><span class="comment">#cgo linux CFLAGS: -DCGO_OS_LINUX=1</span></span><br></pre></td></tr></table></figure>

<h1 id="3-类型转换"><a href="#3-类型转换" class="headerlink" title="3.类型转换"></a>3.类型转换</h1><table>
<thead>
<tr>
<th align="left">C语言类型</th>
<th align="left">CGO类型</th>
<th align="left">Go语言类型</th>
</tr>
</thead>
<tbody><tr>
<td align="left">char</td>
<td align="left">C.char</td>
<td align="left">byte</td>
</tr>
<tr>
<td align="left">singed char</td>
<td align="left">C.schar</td>
<td align="left">int8</td>
</tr>
<tr>
<td align="left">unsigned char</td>
<td align="left">C.uchar</td>
<td align="left">uint8</td>
</tr>
<tr>
<td align="left">short</td>
<td align="left">C.short</td>
<td align="left">int16</td>
</tr>
<tr>
<td align="left">unsigned short</td>
<td align="left">C.ushort</td>
<td align="left">uint16</td>
</tr>
<tr>
<td align="left">int</td>
<td align="left">C.int</td>
<td align="left">int32</td>
</tr>
<tr>
<td align="left">unsigned int</td>
<td align="left">C.uint</td>
<td align="left">uint32</td>
</tr>
<tr>
<td align="left">long</td>
<td align="left">C.long</td>
<td align="left">int32</td>
</tr>
<tr>
<td align="left">unsigned long</td>
<td align="left">C.ulong</td>
<td align="left">uint32</td>
</tr>
<tr>
<td align="left">long long int</td>
<td align="left">C.longlong</td>
<td align="left">int64</td>
</tr>
<tr>
<td align="left">unsigned long long int</td>
<td align="left">C.ulonglong</td>
<td align="left">uint64</td>
</tr>
<tr>
<td align="left">float</td>
<td align="left">C.float</td>
<td align="left">float32</td>
</tr>
<tr>
<td align="left">double</td>
<td align="left">C.double</td>
<td align="left">float64</td>
</tr>
<tr>
<td align="left">size_t</td>
<td align="left">C.size_t</td>
<td align="left">uint</td>
</tr>
</tbody></table>
<h1 id="4-函数调用"><a href="#4-函数调用" class="headerlink" title="4.函数调用"></a>4.函数调用</h1><h1 id="6-实例"><a href="#6-实例" class="headerlink" title="6.实例"></a>6.实例</h1><h1 id="10-编译-链接参数"><a href="#10-编译-链接参数" class="headerlink" title="10.编译/链接参数"></a>10.编译/链接参数</h1><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">因此CGO提供了CFLAGS/CPPFLAGS/CXXFLAGS三种参数，</span><br><span class="line">其中CFLAGS对应C语言编译参数(以.c后缀名)、</span><br><span class="line">CPPFLAGS对应C/C++ 代码编译参数(.c,.cc,.cpp,.cxx)、</span><br><span class="line">CXXFLAGS对应纯C++编译参数(.cc,.cpp,*.cxx)。</span><br></pre></td></tr></table></figure>

<h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><ul>
<li>[1] <a target="_blank" rel="noopener" href="https://books.studygolang.com/advanced-go-programming-book/ch2-cgo/readme.html">Go语言高级编程</a></li>
<li>[2] <a target="_blank" rel="noopener" href="https://github.com/golang-china/gopl-zh">Go语言圣经</a></li>
<li>[3] <a target="_blank" rel="noopener" href="https://strawberryperl.com/">Strawberryperl官网</a></li>
<li>[4] <a target="_blank" rel="noopener" href="https://zh.cppreference.com/w/cpp/compiler_support">gcc编译器对标准支持情况</a></li>
</ul>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://example.com/2020/12/24/2020/2020-12-24-cgo%E4%BD%BF%E7%94%A8/" data-id="ckrn3an7a001920xwhw8ggwq2" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/golang/" rel="tag">golang</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-2020/2020-12-15-BehaviorTree" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2020/12/15/2020/2020-12-15-BehaviorTree/" class="article-date">
  <time datetime="2020-12-14T16:00:00.000Z" itemprop="datePublished">2020-12-15</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2020/12/15/2020/2020-12-15-BehaviorTree/">BehaviorTree</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <p>在制作游戏里面，除了使用FSM，还有一种实现模式：行为树。编写本文用于梳理行为树中的概念，知识点。里面使用到了三方库来编辑行为树(behavior3.com)。行为树主要用于做系统控制的，能通过简单的节点组合，编辑出复杂的逻辑。</p>
<h1 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h1><h1 id="节点"><a href="#节点" class="headerlink" title="节点"></a>节点</h1><h2 id="1-composite"><a href="#1-composite" class="headerlink" title="1. composite"></a>1. composite</h2><p>组合节点，可以连接多个子节点，用于决策行为树走向。</p>
<h3 id="1-1-Sequence-amp"><a href="#1-1-Sequence-amp" class="headerlink" title="1.1. Sequence &amp;"></a>1.1. Sequence &amp;</h3><p>Sequence 节点 顺序执行子节点，当子节点返回b3.SUCCESS直接访问下一个子节点，直到所有子节点都返回b3.SUCCESS，才从当前节点返回b3.SUCCESS，当子节点返回b3.FAILURE，则直接从当前节点返回b3.FAILURE 类似于逻辑与&amp;的概念。</p>
<h3 id="1-2-Priority"><a href="#1-2-Priority" class="headerlink" title="1.2. Priority |"></a>1.2. Priority |</h3><p>Priority 节点 选择执行子节点，当子节点返回b3.FAILURE直接访问下一个子节点，直到所有子节点都返回b3.FAILURE，才从当前节点返回b3.FAILURE，当子节点返回b3.SUCCESS，则直接从当前节点返回b3.SUCCESS 类似于逻辑或|的概念。</p>
<h3 id="1-3-MemSequence-amp"><a href="#1-3-MemSequence-amp" class="headerlink" title="1.3. MemSequence &amp;"></a>1.3. MemSequence &amp;</h3><p>MemSequence 节点 逻辑和Sequence一样，但是这里涉及到一个b3.RUNNING的返回值，就是子节点并不知道执行结果是成功还是失败，需要等后续才知道是否成功。其实就是异步的节点。</p>
<p>对于Sequence节点，当它再次遍历子节点的时候，还是从第一个子节点开始遍历，但是MemSequence却会记住之前在Running的子节点,然后下次遍历的时候，直接从Running的那个子节点开始，这可以很方便的继续之前中断的逻辑决策。</p>
<p>比如一个怪物，它的技能有3段，就可以通过这样的节点来组织。</p>
<h3 id="1-4-MemPriority"><a href="#1-4-MemPriority" class="headerlink" title="1.4. MemPriority |"></a>1.4. MemPriority |</h3><p>可以类似于Priority，加上了Mem前缀的意义，已经在1.3. 章节论述过了。</p>
<h2 id="2-decorators"><a href="#2-decorators" class="headerlink" title="2. decorators"></a>2. decorators</h2><p>装饰节点， 可以连接一个子节点， 用于修饰子节点的返回值</p>
<h3 id="2-1-Repeator"><a href="#2-1-Repeator" class="headerlink" title="2.1. Repeator"></a>2.1. Repeator</h3><p>Repeator 节点，重复执行子节点maxLoop次</p>
<h3 id="2-2-RepeatUntilFailure"><a href="#2-2-RepeatUntilFailure" class="headerlink" title="2.2. RepeatUntilFailure"></a>2.2. RepeatUntilFailure</h3><p>RepeatUnitilFailure 节点 ，重复执行子节点直到子节点返回Failure</p>
<h3 id="2-3-RepeatUntilSuccess"><a href="#2-3-RepeatUntilSuccess" class="headerlink" title="2.3. RepeatUntilSuccess"></a>2.3. RepeatUntilSuccess</h3><p>RepeatUntilSuccess 节点，重复执行子节点直到子节点返回Success</p>
<h2 id="3-condition"><a href="#3-condition" class="headerlink" title="3. condition"></a>3. condition</h2><p>条件节点， 可以用于做出判断并返回不同的值</p>
<h2 id="4-action"><a href="#4-action" class="headerlink" title="4. action"></a>4. action</h2><p>行为节点， 可以执行行为。</p>
<h1 id="行为树应用"><a href="#行为树应用" class="headerlink" title="行为树应用"></a>行为树应用</h1><p>通过一段时间的实践，行为树只负责一些行为模式的切换做支持。</p>
<p>行为模式的切换，只通过一些阈值，事件来驱动做一些策略的修改。</p>
<p>行为树的tick时间限制在1sec一次。</p>
<p>行为模式是直接通过程序来实现，可以制作出来的效果可以让怪物灵巧很多。</p>
<p>在制作的时候，通过4个方面去分析问题：</p>
<ol>
<li><p>分析怪物一共有多少个<strong>行为模式</strong></p>
</li>
<li><p>需要抽象多少种怪物属性提供给行为树；</p>
</li>
<li><p>需要抽象多少种事件提供给行为树；</p>
</li>
<li><p>设计每个行为模式的工作细节，方便今后boss重复使用；</p>
</li>
</ol>
<p>怪物在走的时候，需要增加一些细节表现，防止太生硬。比如，待机的时候，会看一看玩家。而不是那种只会走路的那种。</p>
<h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><ul>
<li>[1] <a target="_blank" rel="noopener" href="https://en.wikipedia.org/wiki/Behavior_tree_(artificial_intelligence,_robotics_and_control)">Wiki行为树</a></li>
<li>[2] <a target="_blank" rel="noopener" href="https://baike.baidu.com/item/%E8%A1%8C%E4%B8%BA%E6%A0%91/22735785?fr=aladdin">百度百科行为树</a></li>
<li>[3] <a target="_blank" rel="noopener" href="https://github.com/behavior3/behavior3editor">behavior3editor_github</a></li>
</ul>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://example.com/2020/12/15/2020/2020-12-15-BehaviorTree/" data-id="ckrn3an79001720xw1zi79v0d" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/AI/" rel="tag">AI</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Game/" rel="tag">Game</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-2020/2020-12-15-go语言并发之道笔记" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2020/12/15/2020/2020-12-15-go%E8%AF%AD%E8%A8%80%E5%B9%B6%E5%8F%91%E4%B9%8B%E9%81%93%E7%AC%94%E8%AE%B0/" class="article-date">
  <time datetime="2020-12-14T16:00:00.000Z" itemprop="datePublished">2020-12-15</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2020/12/15/2020/2020-12-15-go%E8%AF%AD%E8%A8%80%E5%B9%B6%E5%8F%91%E4%B9%8B%E9%81%93%E7%AC%94%E8%AE%B0/">go语言并发之道笔记</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <p>借过同事的一本《go语言并发之道》一直都没有去阅读。我是非常懒惰的，开一篇笔记，督促自己将本书阅读完成。主要是抓举一些概念，然后就是理解如何组织代码。</p>
<p>O’Reily 奥莱利 出版社，原书名：《Concurrency in Go》，IBSN 978-7-5198-2494-5. 图书馆编码 TP312</p>
<ul>
<li><a href="#0-%E5%89%8D%E8%A8%80">0. 前言</a></li>
<li><a href="#1-%E5%B9%B6%E5%8F%91%E6%A6%82%E8%BF%B0">1. 并发概述</a><ul>
<li><a href="#11-%E5%B9%B6%E5%8F%91%E7%9A%84%E9%87%8D%E8%A6%81%E6%80%A7">1.1. 并发的重要性</a></li>
<li><a href="#12-%E5%B9%B6%E5%8F%91%E9%9A%BE%E7%82%B9">1.2. 并发难点</a><ul>
<li><a href="#121-%E7%AB%9E%E4%BA%89%E6%9D%A1%E4%BB%B6">1.2.1. 竞争条件</a></li>
<li><a href="#122-%E5%8E%9F%E5%AD%90%E6%80%A7">1.2.2. 原子性</a></li>
<li><a href="#123-%E5%86%85%E5%AD%98%E8%AE%BF%E9%97%AE%E5%90%8C%E6%AD%A5">1.2.3. 内存访问同步</a></li>
<li><a href="#124-%E6%AD%BB%E9%94%81%E6%B4%BB%E9%94%81%E5%92%8C%E9%A5%A5%E9%A5%BF">1.2.4. 死锁、活锁和饥饿</a><ul>
<li><a href="#1-%E6%AD%BB%E9%94%81deadlock">1. 死锁（deadlock）</a></li>
<li><a href="#2-%E6%B4%BB%E9%94%81livelock">2. 活锁（livelock）</a></li>
<li><a href="#3-%E9%A5%A5%E9%A5%BFhunger">3. 饥饿（hunger）</a></li>
</ul>
</li>
<li><a href="#125-%E7%A1%AE%E5%AE%9A%E5%B9%B6%E5%8F%91%E5%AE%89%E5%85%A8">1.2.5. 确定并发安全</a></li>
<li><a href="#126-%E9%9D%A2%E5%AF%B9%E5%A4%8D%E6%9D%82%E6%80%A7%E7%9A%84%E7%AE%80%E5%8D%95%E6%80%A7">1.2.6. 面对复杂性的简单性</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#2%E5%AF%B9%E4%BD%A0%E7%9A%84%E4%BB%A3%E7%A0%81%E5%BB%BA%E6%A8%A1%E9%80%9A%E4%BF%A1%E9%A1%BA%E5%BA%8F%E8%BF%9B%E7%A8%8B">2.对你的代码建模：通信顺序进程</a><ul>
<li><a href="#%E5%B9%B6%E5%8F%91%E4%BA%8E%E5%B9%B6%E8%A1%8C%E7%9A%84%E5%8C%BA%E5%88%AB">并发于并行的区别</a></li>
<li><a href="#%E4%BB%80%E4%B9%88%E6%98%AFcsp">什么是CSP</a></li>
<li><a href="#go%E8%AF%AD%E8%A8%80%E7%9A%84%E5%B9%B6%E5%8F%91%E5%93%B2%E5%AD%A6">Go语言的并发哲学</a></li>
</ul>
</li>
<li><a href="#3go%E8%AF%AD%E8%A8%80%E5%B9%B6%E5%8F%91%E7%BB%84%E4%BB%B6">3.Go语言并发组件</a><ul>
<li><a href="#goroutine">goroutine</a></li>
<li><a href="#sync%E5%8C%85">sync包</a><ul>
<li><a href="#waitgroup">WaitGroup</a></li>
<li><a href="#%E4%BA%92%E6%96%A5%E9%94%81%E5%92%8C%E8%AF%BB%E5%86%99%E9%94%81">互斥锁和读写锁</a></li>
<li><a href="#cond">cond</a></li>
<li><a href="#once">once</a></li>
<li><a href="#%E6%B1%A0">池</a></li>
</ul>
</li>
<li><a href="#channel">channel</a></li>
<li><a href="#select%E8%AF%AD%E5%8F%A5">select语句</a></li>
<li><a href="#gomaxproces%E6%8E%A7%E5%88%B6">GOMAXPROCES控制</a></li>
</ul>
</li>
<li><a href="#4go%E8%AF%AD%E8%A8%80%E7%9A%84%E5%B9%B6%E5%8F%91%E6%A8%A1%E5%9E%8B">4.Go语言的并发模型</a><ul>
<li><a href="#%E7%BA%A6%E6%9D%9F">约束</a></li>
<li><a href="#for-select%E5%BE%AA%E7%8E%AF">for-select循环</a></li>
<li><a href="#%E9%98%B2%E6%AD%A2goroutine%E6%B3%84%E9%9C%B2">防止goroutine泄露</a></li>
<li><a href="#or-channel">or-channel</a></li>
<li><a href="#%E9%94%99%E8%AF%AF%E5%A4%84%E7%90%86">错误处理</a></li>
<li><a href="#pipeline">pipeline</a><ul>
<li><a href="#%E6%9E%84%E5%BB%BApipeline%E7%9A%84%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5">构建pipeline的最佳实践</a></li>
<li><a href="#%E4%B8%80%E4%BA%9B%E4%BE%BF%E5%88%A9%E7%9A%84%E7%94%9F%E6%88%90%E5%99%A8">一些便利的生成器</a></li>
</ul>
</li>
<li><a href="#%E6%89%87%E5%85%A5%E6%89%87%E5%87%BA">扇入，扇出</a></li>
<li><a href="#or-done-channel">or-done-channel</a></li>
<li><a href="#tee-channel">tee-channel</a></li>
<li><a href="#%E6%A1%A5%E6%8E%A5channel%E6%A8%A1%E5%BC%8F">桥接channel模式</a></li>
<li><a href="#%E9%98%9F%E5%88%97%E6%8E%92%E9%98%9F">队列排队</a></li>
<li><a href="#context%E5%8C%85">context包</a></li>
<li><a href="#%E5%B0%8F%E7%BB%93">小结</a></li>
</ul>
</li>
<li><a href="#5%E5%A4%A7%E8%A7%84%E6%A8%A1%E5%B9%B6%E5%8F%91">5.大规模并发</a><ul>
<li><a href="#%E5%BC%82%E5%B8%B8%E4%BC%A0%E9%80%92">异常传递</a></li>
<li><a href="#%E8%B6%85%E6%97%B6%E5%92%8C%E5%8F%96%E6%B6%88">超时和取消</a></li>
<li><a href="#%E5%BF%83%E8%B7%B3">心跳</a></li>
<li><a href="#%E5%A4%8D%E5%88%B6%E8%AF%B7%E6%B1%82">复制请求</a></li>
<li><a href="#%E9%80%9F%E7%8E%87%E9%99%90%E5%88%B6">速率限制</a></li>
<li><a href="#%E6%B2%BB%E6%84%88%E4%BB%A5%E5%B8%B8%E7%9A%84goroutine">治愈以常的goroutine</a></li>
<li><a href="#%E5%B0%8F%E7%BB%93-1">小结</a></li>
</ul>
</li>
<li><a href="#6-goroutine%E5%92%8Cgo%E8%AF%AD%E8%A8%80%E8%BF%90%E8%A1%8C%E6%97%B6">6 goroutine和Go语言运行时</a><ul>
<li><a href="#%E5%B7%A5%E4%BD%9C%E7%AA%83%E5%8F%96">工作窃取</a><ul>
<li><a href="#%E7%AA%83%E5%8F%96%E4%BB%BB%E5%8A%A1%E8%BF%98%E6%98%AF%E7%BB%AD%E4%BD%93">窃取任务还是续体</a></li>
</ul>
</li>
<li><a href="#%E5%90%91%E5%BC%80%E5%8F%91%E8%80%85%E5%B1%95%E7%A4%BA%E6%89%80%E6%9C%89%E8%BF%99%E4%BA%9B%E4%BF%A1%E6%81%AF">向开发者展示所有这些信息</a></li>
<li><a href="#%E5%B0%BE%E5%A3%B0">尾声</a></li>
</ul>
</li>
<li><a href="#%E5%8F%82%E8%80%83">参考</a></li>
</ul>
<h1 id="0-前言"><a href="#0-前言" class="headerlink" title="0. 前言"></a>0. 前言</h1><p>本书一共6章节。</p>
<p>作者罗列golang中的好处，简洁、编译快速、运行稳定、支持鸭子类型(duck typing)。最重要的还是语言级原生支持并发。</p>
<p>作者在过去几年使用golang做项目，出于在社区里面没有Golang并发编程的综合指南，决定编写这本书。</p>
<p>本书的读者对象</p>
<p>本书不会讲解Golang基础语法。最好能了解过其他语言的并发。</p>
<p>讨论的并发逻辑：常见并发陷阱，golang并发设计原则，golang并发原语中的基础语法，常见并发模式，并发模式的设计，各种工具使用。</p>
<p>各章节的简介</p>
<blockquote>
<ol>
<li>并发概述</li>
</ol>
</blockquote>
<p>Global_Keys<br>从广泛的历史视角说明并发的重要性，讨论并发中的一些难点。简要介绍golang如何解决这些问题。</p>
<p>如果知道并发相关知识，可以跳过本章；</p>
<blockquote>
<ol start="2">
<li>对你的代码建模：通讯顺序进程</li>
</ol>
</blockquote>
<p>论述推动golang设计的一些激励因素。 </p>
<blockquote>
<ol start="3">
<li>golang并发组件</li>
</ol>
</blockquote>
<p>介绍golang并发原语。介绍控制内存访问同步sync包。</p>
<p>通过golang代码并发片段，与其他语言的并发模型对比。有助于完全理解golang的并发实现。</p>
<blockquote>
<ol start="4">
<li>Golang的并发模式</li>
</ol>
</blockquote>
<p>讨论使用Golang原语函数构建合理的模式。</p>
<p>对于已经开始写golang的并发代码，这种是有些用处。</p>
<blockquote>
<ol start="5">
<li>大规模并发</li>
</ol>
</blockquote>
<p>将组合并发模式，设计合理的模型，应用于大型程序、服务和分布式系统中。</p>
<blockquote>
<ol start="6">
<li>goroutine和golang运行时</li>
</ol>
</blockquote>
<p>描述golang中的goroutine如何调度。想了解golang虚拟机的人可以阅读这一章节。</p>
<h1 id="1-并发概述"><a href="#1-并发概述" class="headerlink" title="1. 并发概述"></a>1. 并发概述</h1><h2 id="1-1-并发的重要性"><a href="#1-1-并发的重要性" class="headerlink" title="1.1. 并发的重要性"></a>1.1. 并发的重要性</h2><p>摩尔定理增速会放缓。</p>
<p>Amdahl定律（Gene Amdahl）：并行计算中的加速比是用并行前的执行速度和并行后的执行速度之比来表示的，它表示了在并行化之后的效率提升情况。</p>
<p>阿姆达尔定律是固定负载（计算总量不变时）时的量化标准。可用公式：(Ws+Wp)/(Ws+(Wp/p))来表示。式中Ws,Wp分别表示问题规模的串行分量（问题中不能并行化的那一部分）和并行分量，p表示处理器数量。</p>
<p>当p趋近于无穷大，这意味着无论我们如何增大处理器数目，加速比是无法高于这个数的。</p>
<p><a target="_blank" rel="noopener" href="https://zh.wikipedia.org/wiki/%E9%98%BF%E5%A7%86%E8%BE%BE%E5%B0%94%E5%AE%9A%E5%BE%8B">参考文献</a></p>
<p><a target="_blank" rel="noopener" href="https://imgchr.com/i/rKmdnH"><img src="https://s3.ax1x.com/2020/12/15/rKmdnH.png" alt="rKmdnH.png"></a></p>
<blockquote>
<p>将问题W-&gt;拆分成Ws,Wp两类，也只有Wp能支持被多核优化，产生收益。</p>
</blockquote>
<h2 id="1-2-并发难点"><a href="#1-2-并发难点" class="headerlink" title="1.2. 并发难点"></a>1.2. 并发难点</h2><p>并发代码难写，但是有迹可循。每个人遇到的问题其实都能被归纳总结的。</p>
<h3 id="1-2-1-竞争条件"><a href="#1-2-1-竞争条件" class="headerlink" title="1.2.1. 竞争条件"></a>1.2.1. 竞争条件</h3><p>本应该按照顺序执行的代码，但是分配到不同的并发的处理里面，编写者如果还认为是顺序执行，那就会出现难以预料的结果。</p>
<h3 id="1-2-2-原子性"><a href="#1-2-2-原子性" class="headerlink" title="1.2.2. 原子性"></a>1.2.2. 原子性</h3><p>搞清楚<strong>上下文</strong>概念。</p>
<p>i++</p>
<p>这句话一共分为三步骤：</p>
<p>检索i的值</p>
<p>增加i的值</p>
<p>存储i的值</p>
<p>三个步骤都是原子操作，但是组合起来不一定是原子操作。让组合的这句话能原子操作，取决于这段代码跑在什么上下文中。比如上下文暴漏给多个goroutine就不会是原子操作，而如果只有一个goroutine运行它，那就是原子操作。如果某个操作时原子操作，那就意味着暴漏给多个goroutine跑，也是安全的。</p>
<p>而大多数编写的语句都不是原子操作。在引入并发的时候，如何引入强制保持原子性，粒度如何确定就是考虑的问题。</p>
<h3 id="1-2-3-内存访问同步"><a href="#1-2-3-内存访问同步" class="headerlink" title="1.2.3. 内存访问同步"></a>1.2.3. 内存访问同步</h3><p>在不同goroutine中访问相同一块内存，可以通过使用 sync.Mutex 来做一个访问的独占。</p>
<p>临界区是否操作过于频繁；</p>
<p>临界区设计得有多大；</p>
<h3 id="1-2-4-死锁、活锁和饥饿"><a href="#1-2-4-死锁、活锁和饥饿" class="headerlink" title="1.2.4. 死锁、活锁和饥饿"></a>1.2.4. 死锁、活锁和饥饿</h3><h4 id="1-死锁（deadlock）"><a href="#1-死锁（deadlock）" class="headerlink" title="1. 死锁（deadlock）"></a>1. 死锁（deadlock）</h4><p>死锁至少要出现两把锁；</p>
<p>两把锁调用之间需要间隔一点点时间；</p>
<p>在锁定的顺序两个操作一定是反序的；</p>
<h4 id="2-活锁（livelock）"><a href="#2-活锁（livelock）" class="headerlink" title="2. 活锁（livelock）"></a>2. 活锁（livelock）</h4><p>活锁指的是任务或者执行者没有被阻塞，由于某些条件没有满足，导致一直重复尝试—失败—尝试—失败的过程。处于活锁的实体是在不断的改变状态，活锁有可能自行解开。活锁可以认为是一种特殊的饥饿。</p>
<p>生活中的典型例子： 两个人在窄路相遇，同时向一个方向避让，然后又向另一个方向避让，如此反复。</p>
<p>两个线程，都拿到一份资源，再互相询问需要对方的资源，询问失败之后，将放弃自己的资源，转而使用反方向来尝试，这样两个线程就会刚好旋转起来。而且两个线程都无法执行任何的逻辑。</p>
<h4 id="3-饥饿（hunger）"><a href="#3-饥饿（hunger）" class="headerlink" title="3. 饥饿（hunger）"></a>3. 饥饿（hunger）</h4><p>贪婪的work抢占共享锁以完成整个工作循环，而和平的work则试图只在需要使用的时候才锁定。相同的时间间隔内，和平的work比贪婪的work少处理一半的工作量。</p>
<p>贪婪的work不必要扩大对临界区持有时间，并阻止了和平的work高效工作。</p>
<p>可以通过记录进程速度是否达到预期，检测某个进程是否饥饿。</p>
<p>饥饿会导致程序表现低效。</p>
<h3 id="1-2-5-确定并发安全"><a href="#1-2-5-确定并发安全" class="headerlink" title="1.2.5. 确定并发安全"></a>1.2.5. 确定并发安全</h3><p>在编写函数的时候，需要对函数做一些注解，提醒使用者需要考虑以下问题：</p>
<ul>
<li>谁负责并发？</li>
<li>如何利用并发原语解决这个问题的？</li>
<li>谁负责同步？</li>
</ul>
<h3 id="1-2-6-面对复杂性的简单性"><a href="#1-2-6-面对复杂性的简单性" class="headerlink" title="1.2.6. 面对复杂性的简单性"></a>1.2.6. 面对复杂性的简单性</h3><p>golang的gc在1.8版本开始，gc暂停一般都是 10~100μs</p>
<h1 id="2-对你的代码建模：通信顺序进程"><a href="#2-对你的代码建模：通信顺序进程" class="headerlink" title="2.对你的代码建模：通信顺序进程"></a>2.对你的代码建模：通信顺序进程</h1><h2 id="并发于并行的区别"><a href="#并发于并行的区别" class="headerlink" title="并发于并行的区别"></a>并发于并行的区别</h2><p>宣讲概念，容易让人觉得好为人师，矫情的不谦逊。</p>
<p>Erlang作者Joe Armstrong举例子：</p>
<p><a target="_blank" rel="noopener" href="https://imgchr.com/i/swzFE9"><img src="https://s3.ax1x.com/2021/01/15/swzFE9.jpg" alt="swzFE9.jpg"></a></p>
<p>Concurrent</p>
<p>Two queues and one coffee machine.</p>
<p>Parallel</p>
<p>Two queues and two coffee machines.</p>
<h2 id="什么是CSP"><a href="#什么是CSP" class="headerlink" title="什么是CSP"></a>什么是CSP</h2><p>communicating sequential processes（通讯顺序进程）。</p>
<p><a target="_blank" rel="noopener" href="http://c.biancheng.net/view/5111.html">Go语言CSP：通信顺序进程简述</a></p>
<p>CSP 并发模型是上个世纪七十年代提出的，用于描述两个独立的并发实体通过共享 channel（管道）进行通信的并发模型。</p>
<p>Go语言就是借用 CSP 并发模型的一些概念为之实现并发的，但是Go语言并没有完全实现了 CSP 并发模型的所有理论，仅仅是实现了 process 和 channel 这两个概念。</p>
<p>process 就是Go语言中的 goroutine，每个 goroutine 之间是通过 channel 通讯来实现数据共享。</p>
<h2 id="Go语言的并发哲学"><a href="#Go语言的并发哲学" class="headerlink" title="Go语言的并发哲学"></a>Go语言的并发哲学</h2><p>分辨使用传统锁、channel；</p>
<p><a target="_blank" rel="noopener" href="https://imgchr.com/i/sURMA1"><img src="https://s3.ax1x.com/2021/01/14/sURMA1.png" alt="sURMA1.png"></a></p>
<blockquote>
<p>总结：追求简洁，尽量使用channel，并且认为gorountine的使用是没有成本的。</p>
</blockquote>
<h1 id="3-Go语言并发组件"><a href="#3-Go语言并发组件" class="headerlink" title="3.Go语言并发组件"></a>3.Go语言并发组件</h1><h2 id="goroutine"><a href="#goroutine" class="headerlink" title="goroutine"></a>goroutine</h2><p>开启一个golang的协程。作者8G内存的机器，理论上可以创建数百万个goroutine。而且协程切换上下文的时候，成本比较低。</p>
<h2 id="sync包"><a href="#sync包" class="headerlink" title="sync包"></a>sync包</h2><h3 id="WaitGroup"><a href="#WaitGroup" class="headerlink" title="WaitGroup"></a>WaitGroup</h3><p>可以把它当作线程安全的计数器。Add函数增加计数，Done函数减少计数，Wait函数阻塞，直到计数为0.</p>
<figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> wg sync.WaitGroup</span><br><span class="line">wg.Add(<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">  <span class="keyword">defer</span> wg.Done()</span><br><span class="line">&#125;()</span><br><span class="line">wg.Wait()</span><br></pre></td></tr></table></figure>

<h3 id="互斥锁和读写锁"><a href="#互斥锁和读写锁" class="headerlink" title="互斥锁和读写锁"></a>互斥锁和读写锁</h3><p>互斥锁用于保护临界区资源</p>
<figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> lock sync.Mutex</span><br><span class="line">lock.Lock()</span><br><span class="line">lock.Unlock()</span><br></pre></td></tr></table></figure>

<p>读写锁</p>
<figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> m = sync.RWMutex</span><br><span class="line">m.RLocker()</span><br><span class="line">RWMutex提供了四个方法：</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(*RWMutex)</span> <span class="title">Lock</span> // 写锁定</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(*RWMutex)</span> <span class="title">Unlock</span> // 写解锁</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(*RWMutex)</span> <span class="title">RLock</span> // 读锁定</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(*RWMutex)</span> <span class="title">RUnlock</span> // 读解锁</span></span><br></pre></td></tr></table></figure>

<h3 id="cond"><a href="#cond" class="headerlink" title="cond"></a>cond</h3><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> locker = <span class="built_in">new</span>(sync.Mutex)</span><br><span class="line"><span class="keyword">var</span> cond = sync.NewCond(locker)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">test</span><span class="params">(x <span class="keyword">int</span>)</span></span> &#123;</span><br><span class="line">        cond.L.Lock() <span class="comment">//获取锁</span></span><br><span class="line">        fmt.Println(<span class="string">&quot;aaa: &quot;</span>, x)</span><br><span class="line">        cond.Wait()<span class="comment">//等待通知  暂时阻塞</span></span><br><span class="line">        fmt.Println(<span class="string">&quot;bbb: &quot;</span>, x)</span><br><span class="line">        time.Sleep(time.Second * <span class="number">2</span>)</span><br><span class="line">        cond.L.Unlock()<span class="comment">//释放锁</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">        <span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="number">5</span>; i++ &#123;</span><br><span class="line">                <span class="keyword">go</span> test(i)</span><br><span class="line">        &#125;</span><br><span class="line">        fmt.Println(<span class="string">&quot;start all&quot;</span>)</span><br><span class="line">        time.Sleep(time.Second * <span class="number">1</span>)</span><br><span class="line">        fmt.Println(<span class="string">&quot;broadcast&quot;</span>)</span><br><span class="line">        cond.Signal()   <span class="comment">// 下发一个通知给已经获取锁的goroutine</span></span><br><span class="line">        time.Sleep(time.Second * <span class="number">1</span>)</span><br><span class="line">        cond.Signal()<span class="comment">// 3秒之后 下发一个通知给已经获取锁的goroutine</span></span><br><span class="line">        time.Sleep(time.Second * <span class="number">1</span>)</span><br><span class="line">        cond.Broadcast()<span class="comment">//3秒之后 下发广播给所有等待的goroutine</span></span><br><span class="line">        time.Sleep(time.Second * <span class="number">10</span>)</span><br><span class="line">        fmt.Println(<span class="string">&quot;finish all&quot;</span>)</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h3 id="once"><a href="#once" class="headerlink" title="once"></a>once</h3><p>让一个操作只调用一次，就可以使用这个方式来制作。</p>
<figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">&quot;fmt&quot;</span></span><br><span class="line">	<span class="string">&quot;sync&quot;</span></span><br><span class="line">	<span class="string">&quot;time&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> once sync.Once</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">for</span> i, v := <span class="keyword">range</span> <span class="built_in">make</span>([]<span class="keyword">string</span>, <span class="number">10</span>) &#123;</span><br><span class="line">		once.Do(onces)</span><br><span class="line">		fmt.Println(<span class="string">&quot;count:&quot;</span>, v, <span class="string">&quot;---&quot;</span>, i)</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="number">10</span>; i++ &#123;</span><br><span class="line"></span><br><span class="line">		<span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">			once.Do(onced)</span><br><span class="line">			fmt.Println(<span class="string">&quot;213&quot;</span>)</span><br><span class="line">		&#125;()</span><br><span class="line">	&#125;</span><br><span class="line">	time.Sleep(<span class="number">4000</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">onces</span><span class="params">()</span></span> &#123;</span><br><span class="line">	fmt.Println(<span class="string">&quot;onces&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">onced</span><span class="params">()</span></span> &#123;</span><br><span class="line">	fmt.Println(<span class="string">&quot;onced&quot;</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="池"><a href="#池" class="headerlink" title="池"></a>池</h3><p>池是对于Pool模式的一种并发安全实现。</p>
<p>对外提供Get方法，如果发现池子里面没有空闲的元素，将会新建一个元素出来。</p>
<p>当使用完成了之后，将会需要调用Put方法将内存归还。</p>
<p>在构建池的时候，需要提供给它一个构造元素的函数。这个函数是线程安全的。</p>
<blockquote>
<p>使用场景是这些东西是需要被多个线程共用，而且需求的东西是非常同质化，需要考虑的事情就是new出来，初始化的成本。打个比方：如果需要新建一个db的连接，今后其他的进程还需要使用，这样的情况使用Pool。如果找程序申请一段边长的内存块，那就最好使用new直接搞定。</p>
</blockquote>
<p>需要注意的点：</p>
<ul>
<li>当实例化sync.Pool，使用new方法创建一个成员变量，在调用时是线程安全的。</li>
<li>当你收到了一个来自Get的实例时，不要对所接受的对象的状态做任何的假设。</li>
<li>当你用完了一个Pool中取出来的对象时，一定要调用Put，否则，Pool无法复用这个实例。</li>
<li>Pool内的分布必须大致均匀。</li>
</ul>
<h2 id="channel"><a href="#channel" class="headerlink" title="channel"></a>channel</h2><p>channel是由Hoare的CSP派生出来的同步原语之一。</p>
<p>channel通常使用Stream来命名这种变量。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> dataStream <span class="keyword">chan</span> <span class="keyword">interface</span>&#123;&#125;</span><br><span class="line">dataStream = <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="keyword">interface</span>&#123;&#125;)</span><br><span class="line"><span class="keyword">var</span> recvChan &lt;-<span class="keyword">chan</span> <span class="keyword">interface</span>&#123;&#125;</span><br><span class="line"><span class="keyword">var</span> sendChan &lt;-<span class="keyword">chan</span> <span class="keyword">interface</span>&#123;&#125;</span><br><span class="line">recvChan = dataStream</span><br><span class="line">sendChan = dataStream</span><br><span class="line"></span><br><span class="line">&lt;-writeStream</span><br><span class="line"><span class="comment">// invaslid operation: &lt;- writeStream (receive  from send-only type)</span></span><br></pre></td></tr></table></figure>

<p>上述的例子是构建了一个双向链表，recvChan和sendChan是为了约束数据的流向，防止在生产者场景下读取了数据。</p>
<p>channel里面读取数据的写法如下：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">salutation,ok := &lt;-stringStream</span><br></pre></td></tr></table></figure>

<p>当channel被关闭了，返回的ok也是失败的。</p>
<table>
<thead>
<tr>
<th align="left">操作</th>
<th align="left">Channel状态</th>
<th align="left">结果</th>
</tr>
</thead>
<tbody><tr>
<td align="left">Read</td>
<td align="left">nil</td>
<td align="left">阻塞</td>
</tr>
<tr>
<td align="left"></td>
<td align="left">打开且非空</td>
<td align="left">输出值</td>
</tr>
<tr>
<td align="left"></td>
<td align="left">关闭的</td>
<td align="left">&lt;默认值&gt;,false</td>
</tr>
<tr>
<td align="left"></td>
<td align="left">只读</td>
<td align="left">编译报错</td>
</tr>
<tr>
<td align="left">Write</td>
<td align="left">nil</td>
<td align="left">阻塞</td>
</tr>
<tr>
<td align="left"></td>
<td align="left">打开的但填满</td>
<td align="left">阻塞</td>
</tr>
<tr>
<td align="left"></td>
<td align="left">打开，但不满</td>
<td align="left">写入值</td>
</tr>
<tr>
<td align="left"></td>
<td align="left">关闭的</td>
<td align="left">panic</td>
</tr>
<tr>
<td align="left"></td>
<td align="left">只读</td>
<td align="left">编译报错</td>
</tr>
<tr>
<td align="left">close</td>
<td align="left">nil</td>
<td align="left">panic</td>
</tr>
<tr>
<td align="left"></td>
<td align="left">打开且非空</td>
<td align="left">关闭channel；读取成功，直到通道耗尽，然后读取产生值的默认值</td>
</tr>
<tr>
<td align="left"></td>
<td align="left">打开但空</td>
<td align="left">关闭channel；读到生产者的默认值</td>
</tr>
<tr>
<td align="left"></td>
<td align="left">关闭的</td>
<td align="left">panic</td>
</tr>
<tr>
<td align="left"></td>
<td align="left">只读</td>
<td align="left">编译报错</td>
</tr>
</tbody></table>
<p>如果关闭了channel，其实还是会将里面的内容都读取出来的。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> stringStream <span class="keyword">chan</span> <span class="keyword">string</span></span><br><span class="line">stringStream = <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="keyword">string</span>, <span class="number">1</span>)</span><br><span class="line"><span class="keyword">var</span> recvStream &lt;-<span class="keyword">chan</span> <span class="keyword">string</span></span><br><span class="line"><span class="keyword">var</span> sendStream <span class="keyword">chan</span>&lt;- <span class="keyword">string</span></span><br><span class="line"></span><br><span class="line">recvStream = stringStream</span><br><span class="line">sendStream = stringStream</span><br><span class="line"></span><br><span class="line"><span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">	time.Sleep(<span class="number">2</span> * time.Second)</span><br><span class="line">	<span class="keyword">for</span> &#123;</span><br><span class="line">		<span class="keyword">if</span> val, ok := &lt;-recvStream; ok &#123;</span><br><span class="line">			fmt.Println(val)</span><br><span class="line">		&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">			fmt.Println(<span class="string">&quot;no data&quot;</span>)</span><br><span class="line">			<span class="keyword">break</span></span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;()</span><br><span class="line">sendStream &lt;- <span class="string">&quot;hh&quot;</span></span><br><span class="line">sendStream &lt;- <span class="string">&quot;hh&quot;</span></span><br><span class="line"><span class="built_in">close</span>(stringStream)</span><br><span class="line">time.Sleep(<span class="number">8</span> * time.Second)</span><br></pre></td></tr></table></figure>

<p>对于channel来说，生产者负责发送数据，并且负责销毁。消费者只负责读取，当无法读取的时候，就说明关闭了。</p>
<p>channel是goroutine的黏合剂</p>
<h2 id="select语句"><a href="#select语句" class="headerlink" title="select语句"></a>select语句</h2><p>select是将channel绑定到一块的黏合剂。</p>
<p>select将会选择在其语句段内的某个可工作的通道工作一次。</p>
<h2 id="GOMAXPROCES控制"><a href="#GOMAXPROCES控制" class="headerlink" title="GOMAXPROCES控制"></a>GOMAXPROCES控制</h2><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">runtime.GOMAXPROCS(runtime.NumCPU())</span><br></pre></td></tr></table></figure>

<p>在1.5之前版本，这个值都是设置成1。后面的版本好像都是已经按照cpu个数来决定多少个线程。2</p>
<h1 id="4-Go语言的并发模型"><a href="#4-Go语言的并发模型" class="headerlink" title="4.Go语言的并发模型"></a>4.Go语言的并发模型</h1><p>本章主要是使用3章节中学习到的原语，构建模型出来。</p>
<h2 id="约束"><a href="#约束" class="headerlink" title="约束"></a>约束</h2><p>使用词法阅书将channel从生产者传给消费者的时候，只给只读的接口。</p>
<h2 id="for-select循环"><a href="#for-select循环" class="headerlink" title="for-select循环"></a>for-select循环</h2><p>按照类似这种结构来组织代码</p>
<figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">for</span> &#123;</span><br><span class="line">  <span class="keyword">select</span>&#123;</span><br><span class="line">    <span class="keyword">case</span> str &lt;- recvStream:</span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> _, s := <span class="keyword">range</span>[]<span class="keyword">string</span>&#123;<span class="string">&quot;a&quot;</span>,<span class="string">&quot;b&quot;</span>,<span class="string">&quot;c&quot;</span>&#125;&#123;</span><br><span class="line">  <span class="keyword">select</span> &#123;</span><br><span class="line">    <span class="keyword">case</span> &lt;-done:</span><br><span class="line">      <span class="keyword">return</span></span><br><span class="line">    <span class="keyword">case</span> stringStream &lt;- e:</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="防止goroutine泄露"><a href="#防止goroutine泄露" class="headerlink" title="防止goroutine泄露"></a>防止goroutine泄露</h2><p>goroutine是存在泄露风险，且会造成内存增长。</p>
<p>goroutine有3中情况下种植</p>
<blockquote>
<p>完成工作。<br>由于不可恢复的错误，造成不能工作。<br>当它被告知需要关闭。</p>
</blockquote>
<p>设计原则就是谁创建channel，谁负责将channel关闭。</p>
<h2 id="or-channel"><a href="#or-channel" class="headerlink" title="or-channel"></a>or-channel</h2><p>将一个或多个完成的channel合并到一个完成channel，任何channel关闭时自己也关闭。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="keyword">var</span> or <span class="function"><span class="keyword">func</span><span class="params">(channels ...&lt;-<span class="keyword">chan</span> <span class="keyword">interface</span>&#123;&#125;)</span> &lt;-<span class="title">chan</span> <span class="title">interface</span></span>&#123;&#125;</span><br><span class="line">	or = <span class="function"><span class="keyword">func</span><span class="params">(channels ...&lt;-<span class="keyword">chan</span> <span class="keyword">interface</span>&#123;&#125;)</span> &lt;-<span class="title">chan</span> <span class="title">interface</span></span>&#123;&#125; &#123; <span class="comment">// &lt;1&gt;</span></span><br><span class="line">		<span class="keyword">switch</span> <span class="built_in">len</span>(channels) &#123;</span><br><span class="line">		<span class="keyword">case</span> <span class="number">0</span>: <span class="comment">// &lt;2&gt;</span></span><br><span class="line">			<span class="keyword">return</span> <span class="literal">nil</span></span><br><span class="line">		<span class="keyword">case</span> <span class="number">1</span>: <span class="comment">// &lt;3&gt;</span></span><br><span class="line">			<span class="keyword">return</span> channels[<span class="number">0</span>]</span><br><span class="line">		&#125;</span><br><span class="line"></span><br><span class="line">		orDone := <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="keyword">interface</span>&#123;&#125;)</span><br><span class="line">		<span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123; <span class="comment">// &lt;4&gt;</span></span><br><span class="line">			<span class="keyword">defer</span> <span class="built_in">close</span>(orDone)</span><br><span class="line"></span><br><span class="line">			<span class="keyword">switch</span> <span class="built_in">len</span>(channels) &#123;</span><br><span class="line">			<span class="keyword">case</span> <span class="number">2</span>: <span class="comment">// &lt;5&gt;</span></span><br><span class="line">				<span class="keyword">select</span> &#123;</span><br><span class="line">				<span class="keyword">case</span> &lt;-channels[<span class="number">0</span>]:</span><br><span class="line">				<span class="keyword">case</span> &lt;-channels[<span class="number">1</span>]:</span><br><span class="line">				&#125;</span><br><span class="line">			<span class="keyword">default</span>: <span class="comment">// &lt;6&gt;</span></span><br><span class="line">				<span class="keyword">select</span> &#123;</span><br><span class="line">				<span class="keyword">case</span> &lt;-channels[<span class="number">0</span>]:</span><br><span class="line">				<span class="keyword">case</span> &lt;-channels[<span class="number">1</span>]:</span><br><span class="line">				<span class="keyword">case</span> &lt;-channels[<span class="number">2</span>]:</span><br><span class="line">				<span class="keyword">case</span> &lt;-or(<span class="built_in">append</span>(channels[<span class="number">3</span>:], orDone)...): <span class="comment">// &lt;6&gt;</span></span><br><span class="line">				&#125;</span><br><span class="line">			&#125;</span><br><span class="line">		&#125;()</span><br><span class="line">		<span class="keyword">return</span> orDone</span><br><span class="line">	&#125;</span><br><span class="line">	sig := <span class="function"><span class="keyword">func</span><span class="params">(after time.Duration)</span> &lt;-<span class="title">chan</span> <span class="title">interface</span></span>&#123;&#125; &#123; <span class="comment">// &lt;1&gt;</span></span><br><span class="line">		c := <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="keyword">interface</span>&#123;&#125;)</span><br><span class="line">		<span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">			<span class="keyword">defer</span> <span class="built_in">close</span>(c)</span><br><span class="line">			time.Sleep(after)</span><br><span class="line">		&#125;()</span><br><span class="line">		<span class="keyword">return</span> c</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	start := time.Now() <span class="comment">// &lt;2&gt;</span></span><br><span class="line">	&lt;-or(</span><br><span class="line">		sig(<span class="number">2</span>*time.Hour),</span><br><span class="line">		sig(<span class="number">5</span>*time.Minute),</span><br><span class="line">		sig(<span class="number">1</span>*time.Second),</span><br><span class="line">		sig(<span class="number">1</span>*time.Hour),</span><br><span class="line">		sig(<span class="number">1</span>*time.Minute),</span><br><span class="line">	)</span><br><span class="line">	fmt.Printf(<span class="string">&quot;done after %v&quot;</span>, time.Since(start)) <span class="comment">// &lt;3&gt;</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>这样就能将多个channel的结束，合并到一个channel中，任意一个channel结束了就结束。</p>
<p>后续使用”context包”也能做这个事情。</p>
<h2 id="错误处理"><a href="#错误处理" class="headerlink" title="错误处理"></a>错误处理</h2><p>错误处理核心问题是“谁负责处理错误”？</p>
<p>谁有全景呈现问题的完整信息，就交付给谁来发起对于错误的报告。</p>
<h2 id="pipeline"><a href="#pipeline" class="headerlink" title="pipeline"></a>pipeline</h2><p>不要编写大函数，看待程序应该从两个方面来看待：1.流程；2.处理细节。</p>
<h3 id="构建pipeline的最佳实践"><a href="#构建pipeline的最佳实践" class="headerlink" title="构建pipeline的最佳实践"></a>构建pipeline的最佳实践</h3><p>代码中使用了之前<a href="#%E9%98%B2%E6%AD%A2goroutine%E6%B3%84%E9%9C%B2">防止goroutine泄露</a>写法，防止goroutine无法正常退出。</p>
<p>使用pipeline封装每个stage的处理，可以方便让其能分离出多端独立的逻辑来，然后就能做一些并发的事务了。并且这样做是比较安全的。</p>
<h3 id="一些便利的生成器"><a href="#一些便利的生成器" class="headerlink" title="一些便利的生成器"></a>一些便利的生成器</h3><p>这章节的实例也是编写了两个stage来处理生成器，一个负责发生随机字符，另一个控制需要拿多少个。</p>
<p>本章还通过对比测试，其实在多核的时候，并行计算将会更加快速。</p>
<h2 id="扇入，扇出"><a href="#扇入，扇出" class="headerlink" title="扇入，扇出"></a>扇入，扇出</h2><p>fan-out,fan-in技术。</p>
<p>本章节其实讨论的问题就是，如何处理多个stage里面不能畅快的跑的问题。</p>
<p>扇入其实就是多个流汇成一个流来处理。</p>
<p>扇出就是将一个流分派给多个流来处理了。</p>
<p>一个处理的pipeline，中间有很重的处理过程，这样只能拓宽这个处理的stage，而负载轻的可以使用少量的stage来处理。</p>
<p>注意：</p>
<p>如果结果到达的顺序不重要，循环独立运行性很重要。</p>
<h2 id="or-done-channel"><a href="#or-done-channel" class="headerlink" title="or-done-channel"></a>or-done-channel</h2><p>用于处理已经发起了退出操作，但是channel的数据需要处理完。普通写法比较直观，但是最好还是将代码封装出来，返回一个输出式的channel，外层处理逻辑者比较好写。</p>
<h2 id="tee-channel"><a href="#tee-channel" class="headerlink" title="tee-channel"></a>tee-channel</h2><p>类似Unix系统中的tee函数，输入的内容可以在屏幕上输出，并且也输出到一些设定好的文件里面。这种模式其实就是将一份数据并发的分配给两个channel，然后出发后续他们的处理。</p>
<h2 id="桥接channel模式"><a href="#桥接channel模式" class="headerlink" title="桥接channel模式"></a>桥接channel模式</h2><p>需要从这个结构里面将其中的channel拿出来，直接写逻辑。使用这个模式就式为了完成这项工作。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;- <span class="keyword">chan</span>  &lt;- <span class="keyword">chan</span>  <span class="keyword">interface</span>&#123;&#125;</span><br></pre></td></tr></table></figure>

<p>里面也使用了orDone方式读取 &lt;- chan interface{}</p>
<h2 id="队列排队"><a href="#队列排队" class="headerlink" title="队列排队"></a>队列排队</h2><p>有时候，在队列没有准备好的时候，就开始接受请求很有用，这种情况叫做队列。</p>
<p>队列的真正用途是将stage分离，以便一个stage的运行时间不会影响另一个stage的运行时间。以这种方式解耦stage，然后级联以改变整个系统的运行时行为。</p>
<p>这里文中举了个例子，写文件io的，先大量的调用bufio.Writer将内容写入到缓冲区，直到累积到一定程度开始写入硬盘。这个速度提升大概有3倍。但是这样有一些让内存消耗大一些。</p>
<blockquote>
<p>利特尔法则</p>
</blockquote>
<ul>
<li>L = 系统中平均负载数。</li>
<li>$\lambda$ = 负载的平均到达率。</li>
<li>W = 负载在系统中花费的平均时间。</li>
</ul>
<p>L = $\lambda W$</p>
<p>这个等式应用于稳定系统，稳定系统的定义就是输入管道的速率和输出的速率相等。</p>
<p>$nL = \lambda nW$</p>
<p>$L = \lambda \sum_{i=1}^{\infty} Wi$</p>
<p>通过利特尔法则，我们已经证明了队列不会有助于减少在系统中所花费的时间。你的管道只会和最慢的stage一样快。</p>
<p>利特尔法则无法预知处理请求的失败。</p>
<p>队列可能会很有用，但是它是复杂的，作者建议作为最后的优化手段。</p>
<h2 id="context包"><a href="#context包" class="headerlink" title="context包"></a>context包</h2><p>由于某种原因（超时，或者强制退出）我们希望中止这个goroutine的计算任务，那么就用得到这个Context了。</p>
<p>Context 的调用应该是链式的，通过WithCancel，WithDeadline，WithTimeout或WithValue派生出新的 Context。当父 Context 被取消时，其派生的所有 Context 都将取消。</p>
<p>通过context.WithXXX都将返回新的 Context 和 CancelFunc。调用 CancelFunc 将取消子代，移除父代对子代的引用，并且停止所有定时器。未能调用 CancelFunc 将泄漏子代，直到父代被取消或定时器触发。go vet工具检查所有流程控制路径上使用 CancelFuncs。</p>
<p>创建context的时候，需要可能需要使用这两个接口。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 一般用于根context创建</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">Background</span><span class="params">()</span> <span class="title">Context</span></span></span><br><span class="line"><span class="comment">// 一般用于做占位符，现在还悬而未决的</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">TODO</span><span class="params">()</span> <span class="title">Context</span></span></span><br></pre></td></tr></table></figure>

<p>创建的时候，Cancle/Deadline/Timeout/Value这四类。</p>
<h2 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h2><p>模式其实就是抽象出运行的模型，将具体逻辑从运行流程模型中分离出来。这样写逻辑的人只需要按照这个里面的范式来制作内容。 </p>
<h1 id="5-大规模并发"><a href="#5-大规模并发" class="headerlink" title="5.大规模并发"></a>5.大规模并发</h1><h2 id="异常传递"><a href="#异常传递" class="headerlink" title="异常传递"></a>异常传递</h2><p>在并发系统，特别是分布式系统中，可能会出现难于理解的错误。需要在制作的时候就考虑：如何将这些错误通过分布式系统传递出来，如何将错误呈现给使用者。</p>
<p>呈现异常关键信息：</p>
<ol>
<li>发生了什么；</li>
<li>发生的时间、什么位置（调用堆栈-debug.Stack()）；</li>
<li>对用户友好的信息（最好文本方式，而且是一行）；</li>
<li>告诉用户如何获得更多信息（可以考虑将相关的聚合信息提供出来）；</li>
</ol>
<h2 id="超时和取消"><a href="#超时和取消" class="headerlink" title="超时和取消"></a>超时和取消</h2><p>为什么要存在超时呢？</p>
<ol>
<li>系统饱和</li>
<li>陈旧数据</li>
</ol>
<p>数据有窗口期，如果事先知道时间可以使用context.WithTimeout/context.WithDeadline。如果不知道，可以采取 context.WithCancel</p>
<ol start="3">
<li>试图防止死锁</li>
</ol>
<p>尝试等待一段时间，如果没有将会解开锁定，从而使死锁变成活锁。</p>
<p>并发进程可能被取消的原因</p>
<ol>
<li>超时</li>
<li>用户干预</li>
<li>父进程取消</li>
<li>复制请求（第5章专门论述）</li>
</ol>
<p>具体可以查看P184的 图5-1,图5-2；</p>
<p>描述了当请求复制请求的情况。</p>
<p>第一种情况建议在下游goroutine接受第一个处理结果，或者最后一个处理结果。</p>
<p>向父goroutine确认权限，是stage A做完事情，还需要找发生器确认授权，然后才能写入stage B。在实际开发中很少这么来处理，原因来自于这样编写非常复杂。</p>
<h2 id="心跳"><a href="#心跳" class="headerlink" title="心跳"></a>心跳</h2><p>心跳分类</p>
<ol>
<li>工作间隔时间心跳</li>
<li>工作单元开始时心跳</li>
</ol>
<p>对于任何长时间运行或者需要被测试的goroutine，作者强烈建议使用这个模式。</p>
<h2 id="复制请求"><a href="#复制请求" class="headerlink" title="复制请求"></a>复制请求</h2><p>程序处理http请求的时候，可以将这个分配给多个进程、程序或者服务器。优点是更快的拿到结果，缺点是需要维护很多实例，而且消耗更多资源。</p>
<h2 id="速率限制"><a href="#速率限制" class="headerlink" title="速率限制"></a>速率限制</h2><p>用于控制http请求时候，不能无限制的对外提供请求资源。否则会容易被攻击。DDoS—分布式拒绝服务攻击。</p>
<p>即使是正常用户，如果用户足够多，也会出现负载异常，造成死亡螺旋。</p>
<p>go语言限速是基于令牌桶算法。</p>
<p>原理：</p>
<p>构造令牌桶，桶有5的深度；</p>
<p>每次需要做事情的时候，需要从桶里面拿到令牌，否则就需要再次尝试；</p>
<p>当用完我们多少时间内补充令牌，有点类似CD；</p>
<h2 id="治愈以常的goroutine"><a href="#治愈以常的goroutine" class="headerlink" title="治愈以常的goroutine"></a>治愈以常的goroutine</h2><p>长期运行的后台程序中，经常有那种长时间运行的goroutine。处于阻塞状态，等待某个数据到达，唤醒它们。需要建立机制监控是否处在健康状态。万一出问题的时候，还需要建立机制能重启。</p>
<p>Erlang语言里面有那种监控树 supervisor 也有类似模式。其实最好是能在golang语言本身上构建这样的体系。</p>
<h2 id="小结-1"><a href="#小结-1" class="headerlink" title="小结"></a>小结</h2><p>本章介绍的方法用于保持系统的稳定和易于理解。</p>
<h1 id="6-goroutine和Go语言运行时"><a href="#6-goroutine和Go语言运行时" class="headerlink" title="6 goroutine和Go语言运行时"></a>6 goroutine和Go语言运行时</h1><h2 id="工作窃取"><a href="#工作窃取" class="headerlink" title="工作窃取"></a>工作窃取</h2><p>Go语言将会为你调度多个goroutine在不同的系统线程上运行，算法就被称为工作窃取策略。</p>
<p>初步方案是N个处理器，X个任务会被公平调度策略中，每个处理器都获得X/N个任务。但是这样会出现一些问题，比如某项任务比较重，造成其他的CPU会空闲。而且如果任务1依赖于任务4的输出，而它们被分配到不同的P里面，也会造成P的阻塞。</p>
<p>解决办法是创建一个集中队列，让处理器都共享。</p>
<p>工作窃取算法原则：</p>
<ol>
<li>在fork点，将任务添加到与线程关联的双端队列的尾部。</li>
<li>如果线程空闲，则选择一个随机线程，从它的关联双端队列头部窃取工作。</li>
<li>如果在未准备好的join点（即与其同步的goroutine还没有完成），则将工作从线程的双端队列尾部出战。</li>
<li>如果线程的双端队列是空的，则：<br>a. 暂停加入<br>b. 从随机线程关联的双端队列中窃取工作。</li>
</ol>
<h3 id="窃取任务还是续体"><a href="#窃取任务还是续体" class="headerlink" title="窃取任务还是续体"></a>窃取任务还是续体</h3><p>go语言中，goroutine就是任务；</p>
<p>在goroutine之后的一切都被称为续体。</p>
<p>续体窃取被认为优于任务窃取，最好是对续体而不是goroutine进行队列。</p>
<h2 id="向开发者展示所有这些信息"><a href="#向开发者展示所有这些信息" class="headerlink" title="向开发者展示所有这些信息"></a>向开发者展示所有这些信息</h2><p>在开发过程中其实很简单的使用了go func，其背后有非常复杂的调度算法。</p>
<h2 id="尾声"><a href="#尾声" class="headerlink" title="尾声"></a>尾声</h2><p>先学习基本用法，之后再来谈模式，然后是底层运行的原理。</p>
<h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><ul>
<li>[1] <a target="_blank" rel="noopener" href="http://katherine.cox-buday.com/concurrency-in-go">本书源码下载地址</a></li>
<li>[2] <a target="_blank" rel="noopener" href="https://github.com/kat-co/concurrency-in-go-src">源码的github地址</a></li>
<li>[3] <a target="_blank" rel="noopener" href="https://joearms.github.io/published/2013-04-05-concurrent-and-parallel-programming.html">erlang作者谈论并发和并行</a></li>
<li>[4] <a target="_blank" rel="noopener" href="https://baike.baidu.com/item/CSP/9076083?fr=aladdin">通讯顺序进程</a></li>
<li>[5] <a target="_blank" rel="noopener" href="https://latex.91maths.com/">在线LaTex工具</a></li>
<li>[6] <a target="_blank" rel="noopener" href="https://juejin.cn/post/6844904070667321357">深入理解Golang之context</a></li>
<li>[7] <a target="_blank" rel="noopener" href="https://deepzz.com/post/golang-context-package-notes.html">快速掌握 Golang context 包</a></li>
<li>[8] <a target="_blank" rel="noopener" href="https://www.cnblogs.com/yjf512/p/10399190.html">golang中Context的使用场景</a></li>
<li>[9] <a target="_blank" rel="noopener" href="https://liushuchun.gitbooks.io/golang/content/govet/govet.html">go vet工具</a></li>
</ul>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://example.com/2020/12/15/2020/2020-12-15-go%E8%AF%AD%E8%A8%80%E5%B9%B6%E5%8F%91%E4%B9%8B%E9%81%93%E7%AC%94%E8%AE%B0/" data-id="ckrn3an7q002g20xw3ger291l" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/golang/" rel="tag">golang</a></li></ul>

    </footer>
  </div>
  
</article>


  


  <nav id="page-nav">
    
    <a class="extend prev" rel="prev" href="/">&amp;laquo; Prev</a><a class="page-number" href="/">1</a><span class="page-number current">2</span><a class="page-number" href="/page/3/">3</a><a class="page-number" href="/page/4/">4</a><a class="page-number" href="/page/5/">5</a><a class="extend next" rel="next" href="/page/3/">Next &amp;raquo;</a>
  </nav>

</section>
        
          <aside id="sidebar">
  
    

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Tags</h3>
    <div class="widget">
      <ul class="tag-list" itemprop="keywords"><li class="tag-list-item"><a class="tag-list-link" href="/tags/3D/" rel="tag">3D</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/AI/" rel="tag">AI</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/C/" rel="tag">C++</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Game/" rel="tag">Game</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Go/" rel="tag">Go</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Linux/" rel="tag">Linux</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Math/" rel="tag">Math</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Server/" rel="tag">Server</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Unreal-Engine4/" rel="tag">Unreal Engine4</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/git/" rel="tag">git</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/golang/" rel="tag">golang</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/guitar/" rel="tag">guitar</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/node-js/" rel="tag">node.js</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/protobuf/" rel="tag">protobuf</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/python/" rel="tag">python</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/recast/" rel="tag">recast</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/redis/" rel="tag">redis</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/type/" rel="tag">type</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/vscode/" rel="tag">vscode</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E8%BF%90%E7%BB%B4/" rel="tag">运维</a></li></ul>
    </div>
  </div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Tag Cloud</h3>
    <div class="widget tagcloud">
      <a href="/tags/3D/" style="font-size: 10px;">3D</a> <a href="/tags/AI/" style="font-size: 11.67px;">AI</a> <a href="/tags/C/" style="font-size: 15px;">C++</a> <a href="/tags/Game/" style="font-size: 18.33px;">Game</a> <a href="/tags/Go/" style="font-size: 13.33px;">Go</a> <a href="/tags/Linux/" style="font-size: 13.33px;">Linux</a> <a href="/tags/Math/" style="font-size: 11.67px;">Math</a> <a href="/tags/Server/" style="font-size: 16.67px;">Server</a> <a href="/tags/Unreal-Engine4/" style="font-size: 10px;">Unreal Engine4</a> <a href="/tags/git/" style="font-size: 10px;">git</a> <a href="/tags/golang/" style="font-size: 20px;">golang</a> <a href="/tags/guitar/" style="font-size: 10px;">guitar</a> <a href="/tags/node-js/" style="font-size: 10px;">node.js</a> <a href="/tags/protobuf/" style="font-size: 10px;">protobuf</a> <a href="/tags/python/" style="font-size: 10px;">python</a> <a href="/tags/recast/" style="font-size: 11.67px;">recast</a> <a href="/tags/redis/" style="font-size: 10px;">redis</a> <a href="/tags/type/" style="font-size: 10px;">type</a> <a href="/tags/vscode/" style="font-size: 10px;">vscode</a> <a href="/tags/%E8%BF%90%E7%BB%B4/" style="font-size: 16.67px;">运维</a>
    </div>
  </div>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Archives</h3>
    <div class="widget">
      <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2021/07/">July 2021</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2021/06/">June 2021</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2021/04/">April 2021</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2021/03/">March 2021</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2021/01/">January 2021</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2020/12/">December 2020</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2020/11/">November 2020</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/03/">March 2019</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/11/">November 2018</a></li></ul>
    </div>
  </div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Recent Posts</h3>
    <div class="widget">
      <ul>
        
          <li>
            <a href="/2021/07/19/2021/2021-07-19-etcd-learn/">go-etcd阅读笔记</a>
          </li>
        
          <li>
            <a href="/2021/07/19/2021/2021-07-19-socketop-learn/">REUSEPORT-REUSEADDR-学习</a>
          </li>
        
          <li>
            <a href="/2021/06/22/2021/2021-06-22-go-ethereum-learn/">go-ethereum阅读笔记</a>
          </li>
        
          <li>
            <a href="/2021/06/21/2021/2021-06-21-server%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7/">server测试工具</a>
          </li>
        
          <li>
            <a href="/2021/06/09/2021/2021-06-09-pprof-doc/">go-pprof</a>
          </li>
        
      </ul>
    </div>
  </div>

  
</aside>
        
      </div>
      <footer id="footer">
  
  <div class="outer">
    <div id="footer-info" class="inner">
      &copy; 2021 Abel Sean<br>
      Powered by <a href="http://hexo.io/" target="_blank">Hexo</a>
    </div>
  </div>
</footer>
    </div>
    <nav id="mobile-nav">
  
    <a href="/" class="mobile-nav-link">Home</a>
  
    <a href="/archives" class="mobile-nav-link">Archives</a>
  
</nav>
    

<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>


  
<link rel="stylesheet" href="/fancybox/jquery.fancybox.css">

  
<script src="/fancybox/jquery.fancybox.pack.js"></script>




<script src="/js/script.js"></script>




  </div>
</body>
</html>